DA analysis with Milo
We test for differential abundance between healthy and cirrhotic livers. We start by defining neighbourhoods with refined sampling on the KNN graph. We inspect the size of neighbourhoods.
nhoodDistances(liver_milo)
named list()
Then we make a design matrix for the differential test, assigning samples to conditions.
liver_meta <- as.tibble(colData(liver_milo)[,c("dataset","condition")])
`as.tibble()` is deprecated as of tibble 2.0.0.
Please use `as_tibble()` instead.
The signature and semantics have changed, see `?as_tibble`.
[90mThis warning is displayed once every 8 hours.[39m
[90mCall `lifecycle::last_warnings()` to see where this warning was generated.[39m
liver_meta <- distinct(liver_meta) %>%
mutate(condition=factor(condition, levels=c("Uninjured", "Cirrhotic"))) %>%
column_to_rownames("dataset")
Now we can count cells in neighbourhoods and perform the DA test.
milo_res <- testNhoods(liver_milo, design = ~ condition, design.df = liver_meta, fdr.weighting = "k-distance")
Performing spatial FDR correction withk-distance weighting
write_csv(milo_res,"/nfs/team205/ed6/data/Ramachandran2019_liver/liver_results_20201008.csv")
cannot open file '/nfs/team205/ed6/data/Ramachandran2019_liver/liver_results_20201008.csv': Operation not permittedError in open.connection(path, "wb") : cannot open the connection
Parsed with column specification:
cols(
logFC = [32mcol_double()[39m,
logCPM = [32mcol_double()[39m,
F = [32mcol_double()[39m,
PValue = [32mcol_double()[39m,
FDR = [32mcol_double()[39m,
Nhood = [32mcol_double()[39m,
SpatialFDR = [32mcol_double()[39m,
annotation_indepth = [31mcol_character()[39m,
annotation_indepth_fraction = [32mcol_double()[39m
)
Exploration of DA results
We can start by looking at some basic stats

The distribution of P-values looks sensible and from the volcano plot we can see that we have identified some DA neighbourhoods at 10% FDR. We can visualize DA neighbourhoods building an abstracted graph
liver_milo <- buildNhoodGraph(liver_milo)
plotNhoodGraphDA(liver_milo, milo_res, alpha = 0.05)
Making figures for the manuscript
colourCount = length(unique(liver_milo$annotation_lineage))
getPalette = colorRampPalette(brewer.pal(9, "Spectral"))
umap_df <- data.frame(reducedDim(liver_milo, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")
umap1 <- cbind(umap_df, annotation_lineage=liver_milo$annotation_lineage) %>%
ggplot(aes(UMAP_1, UMAP_2, color=as.character(annotation_lineage))) +
geom_point(size=0.1, alpha=0.5) +
ggrepel::geom_text_repel(data = . %>%
group_by(annotation_lineage) %>%
summarise(UMAP_1=mean(UMAP_1), UMAP_2=mean(UMAP_2)),
aes(label=annotation_lineage), color="black", size=6
) +
scale_color_manual(values=getPalette(colourCount)) +
guides(color="none") +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
theme_classic(base_size = 22) +
theme(axis.text = element_blank(), axis.ticks = element_blank(),
legend.text = element_text(size=18), legend.title = element_text(size=20))
umap2 <-
cbind(umap_df, condition=as.character(liver_milo$condition)) %>%
ggplot(aes(UMAP_1, UMAP_2, color=condition)) +
geom_point(size=0.1, alpha=0.5) +
scale_color_brewer(palette="Set1", name='') +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
guides(color='none') +
facet_wrap(condition~., ncol=1) +
theme_nothing() +
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
strip.background = element_rect(color=NA), strip.text = element_text(size=16))
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
legend.text = element_text(size=18), legend.title = element_text(size=20))
List of 5
$ axis.text : list()
..- attr(*, "class")= chr [1:2] "element_blank" "element"
$ axis.ticks : list()
..- attr(*, "class")= chr [1:2] "element_blank" "element"
$ legend.text :List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : num 18
..$ hjust : NULL
..$ vjust : NULL
..$ angle : NULL
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
$ legend.title :List of 11
..$ family : NULL
..$ face : NULL
..$ colour : NULL
..$ size : num 20
..$ hjust : NULL
..$ vjust : NULL
..$ angle : NULL
..$ lineheight : NULL
..$ margin : NULL
..$ debug : NULL
..$ inherit.blank: logi FALSE
..- attr(*, "class")= chr [1:2] "element_text" "element"
$ legend.position: num [1:2] 0.9 0.9
- attr(*, "class")= chr [1:2] "theme" "gg"
- attr(*, "complete")= logi FALSE
- attr(*, "validate")= logi TRUE
nh_graph_pl <- plotNhoodGraphDA(liver_milo, milo_res, alpha = 0.1) +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24)) +
coord_fixed()
invalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generated
fig4_top <- (umap1 | umap2 | nh_graph_pl) +
plot_layout(widths = c(3,1,3))
fig4_top +
ggsave("~/milo_output/liver_embedding.pdf", width=15, height = 10)

Next, we can check the cell types where we observe most differences between healthy and cirrhotic cells, by taking the most frequent cell type in each neighbourhood.
#' Add annotation of most frequent cell type per nhood to milo results table
add_nhood_coldata_to_res <- function(milo, milo_res, coldata_col){
nhood_counts <- sapply(seq_along(nhoods(milo)), function(x) table(colData(milo)[as.vector(nhoods(milo)[[x]]), coldata_col]))
nhood_counts <- t(nhood_counts)
rownames(nhood_counts) <- seq_along(nhoods(milo))
max_val <- apply(nhood_counts, 1, function(x) colnames(nhood_counts)[which.max(x)])
max_frac <- apply(nhood_counts, 1, function(x) max(x)/sum(x))
milo_res[coldata_col] <- max_val
milo_res[paste0(coldata_col, "_fraction")] <- max_frac
return(milo_res)
}
milo_res <- add_nhood_coldata_to_res(liver_milo, milo_res, "annotation_indepth")
milo_res$annotation_lineage.x <- NULL
milo_res$annotation_lineage.y <- NULL
milo_res$annotation_lineage <- NULL
anno_df <- data.frame(liver_milo@colData) %>%
distinct(annotation_lineage, annotation_indepth)
milo_res <- left_join(milo_res, anno_df, by="annotation_indepth")
We first check that neighbourhoods are quite homogeneous

I can recover all the clusters where DA was detected in the original paper (see all the barplots for each lineage) and more! All in a single analysis, and without knowing where the subclusters are. Let’s bear in mind that positive logFC –> more cirrhotic, negative logFC —> more healthy
paper_DA <- list(cirrhotic=c("MPs (4)","MPs (5)",
"Endothelia (6)", "Endothelia (7)",
"Mes (3)",
"Tcells (2)",
"Myofibroblasts"
),
healthy=c("MPs (7)",
"Endothelia (1)",
"Tcells (1)", "Tcells (3)","Tcells (1)",
"ILCs (1)"
)
)
expDA_df <- bind_rows(
data.frame(annotation_indepth = paper_DA[["cirrhotic"]], pred_DA="cirrhotic"),
data.frame(annotation_indepth = paper_DA[["healthy"]], pred_DA="healthy")
)
pl1 <- milo_res %>%
left_join(expDA_df) %>%
mutate(is_signif = ifelse(SpatialFDR < 0.1, 1, 0)) %>%
mutate(logFC_color = ifelse(is_signif==1, logFC, NA)) %>%
arrange(annotation_lineage) %>%
mutate(Nhood=factor(Nhood, levels=unique(Nhood))) %>%
ggplot(aes(annotation_indepth, logFC, color=logFC_color)) +
scale_color_gradient2() +
guides(color="none") +
xlab("annotation") + ylab("Log Fold Change") +
ggbeeswarm::geom_quasirandom(alpha=1) +
coord_flip() +
facet_grid(annotation_lineage~., scales="free", space="free") +
theme_bw(base_size=22) +
theme(strip.text.y = element_text(angle=0),
axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(),
)
Joining, by = "annotation_indepth"
pl2 <- milo_res %>%
left_join(expDA_df) %>%
# dplyr::filter(!is.na(pred_DA)) %>%
group_by(annotation_indepth) %>%
summarise(pred_DA=dplyr::first(pred_DA), annotation_lineage=dplyr::first(annotation_lineage)) %>%
mutate(end=ifelse(pred_DA=="healthy", 0, 1),
start=ifelse(pred_DA=="healthy", 1, 0)) %>%
ggplot(aes(annotation_indepth, start, xend = annotation_indepth, yend = end, color=pred_DA)) +
geom_segment(size=1,arrow=arrow(length = unit(0.1, "npc"), type="closed")) +
coord_flip() +
xlab("annotation") +
facet_grid(annotation_lineage~.,
# annotation_lineage~"Ramachandran et al.\nDA predictions",
scales="free", space="free") +
# guides(color="none") +
scale_color_brewer(palette="Set1", direction = -1,
labels=c("enriched in cirrhotic", "enriched in healthy"),
na.translate = F,
name="Ramachandran et al.\nDA predictions") +
guides(color=guide_legend(ncol = 1)) +
theme_bw(base_size=22) +
ylim(-0.1,1.1) +
theme(strip.text.y = element_blank(),strip.text.x = element_text(angle=90),
plot.margin = unit(c(0,0,0,0), "cm"), panel.grid = element_blank(),
axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = "bottom")
Joining, by = "annotation_indepth"
`summarise()` ungrouping output (override with `.groups` argument)
fig4_bleft <- (pl2 + pl1 +
plot_layout(widths=c(1,10), guides = "collect") & theme(legend.position = 'top', legend.justification = 0))
fig4_bleft +
ggsave("~/milo_output/liver_DAcomparison.pdf", width=8, height = 13)

Close-up on Endothelial lineage
# endo_milo <- scater::runPCA(endo_milo, subset_row=endo_hvgs, ncomponents=11)
endo_milo <- scater::runUMAP(liver_milo[,liver_milo$annotation_lineage=="Endothelia"], dimred='PCA')
umap_df <- data.frame(reducedDim(endo_milo, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")
endo_umap <- cbind(umap_df, condition=endo_milo$condition) %>%
ggplot(aes(UMAP_1, UMAP_2, color=condition)) +
geom_point(size=0.3, alpha=0.5) +
scale_color_brewer(palette="Set1", name='') +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
guides(color="none") +
facet_wrap(condition~., ncol=1) +
theme_nothing() +
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
strip.background = element_rect(color=NA), strip.text = element_text(size=16))
endo_umap

liver_milo2 <- liver_milo
subset.nhoods <- str_detect(milo_res$annotation_indepth, "Endo")
reducedDim(liver_milo2, "UMAP")[colnames(endo_milo),] <- reducedDim(endo_milo, "UMAP")
endo_gr <-
plotNhoodGraphDA(
liver_milo2, milo_res,
subset.nhoods = subset.nhoods,
# subset.nhoods =subset.nhoods[1:(length(subset.nhoods)-1)],
alpha = 0.1
) +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24))
invalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generated
fig4_bright1 <- ((endo_umap + endo_gr ) +
plot_layout(widths = c(1,2),
guides = "collect"
))
fig4_bright1 +
ggsave("~/milo_output/liver_endoGraph.pdf", width=9, height = 5)

Differential expression between DA neighbourhoods
I want to merge overlapping nhoods with significant DA and the same direction of logFC, and then test for differential expression between cells in up and down nhoods (I guess you could also do up or down VS all the rest). This allows us to perform a comparison without further clustering.
endo_milo <- liver_milo[,which(liver_milo$annotation_lineage=="Endothelia")]
endo_res <- dplyr::filter(milo_res, annotation_lineage=="Endothelia")
rownames(endo_res) <- rownames(milo_res)[which(milo_res$annotation_lineage=="Endothelia")]
## keep HV genes expressed in at least 5% of endothelial cells
endo_hvg_cnts <- counts(liver_milo)[hvgs,liver_milo$annotation_lineage=="Endothelia"]
Error in counts(liver_milo)[hvgs, liver_milo$annotation_lineage == "Endothelia"] :
object 'hvgs' not found
# rownames(milo_res) <- names(nhoods(liver_milo)) ## If I don't set the nhood index as name the grouping doesn't
nhood_markers <- findNhoodMarkers(liver_milo, milo_res, overlap=1, assay="logcounts", return.groups = TRUE,
subset.row = endo_hvgs,
subset.nhoods = str_detect(milo_res$annotation_indepth, "Endo"))
Found 1335 DA neighbourhoods at FDR 10%
Nhoods aggregated into 2 groups
sum(nhood_markers$dge$adj.P.Val_1 < 0.01)
[1] 572
marker_genes <- nhood_markers$dge %>%
dplyr::filter(adj.P.Val_1 < 0.01) %>%
pull(GeneID)
liver_milo <- calcNhoodExpression(liver_milo, subset.row = marker_genes)
highlight_genes <- c("PLVAP", "SOX14", "VWA1", "ACKR1",
"CLEC4G", "CLEC4M", "STAB2", "MRC1",
"CD14", "CCL21", "SOX17", "WNT2", "RSPO3", "AIF1L",
"PROX1", "PDPN","CPE", "CD320")
fig4_bbright <- plotNhoodExpressionDA(liver_milo, milo_res, marker_genes, cluster_features = TRUE,
alpha = 0.1,
scale_to_1 = TRUE,
subset.nhoods = milo_res$annotation_lineage=="Endothelia",
highlight_features = highlight_genes, show_rownames = FALSE
) +
ylab("DE genes") +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24))
Some elements of highlight_features are not in features and will not be highlighted.
Missing features: PLVAP, SOX14, CD14, CCL21, SOX17, WNT2, RSPO3, AIF1L, PDPN, CPE
Customize plotting for paper figure
x <- liver_milo
da.res <- milo_res
cluster_features = TRUE
alpha = 0.1
scale_to_1 = TRUE
subset.nhoods = milo_res$annotation_lineage=="Endothelia"
features <- marker_genes
expr_mat <- nhoodExpression(x)[features,]
colnames(expr_mat) <- 1:length(nhoods(x))
## Get nhood expression matrix
if (!is.null(subset.nhoods)) {
expr_mat <- expr_mat[,subset.nhoods, drop=FALSE]
}
if (!isFALSE(scale_to_1)) {
expr_mat <- t(apply(expr_mat, 1, function(x) (x - min(x))/(max(x)- min(x))))
}
rownames(expr_mat) <- sub(pattern = "-", replacement = ".", rownames(expr_mat)) ## To avoid problems when converting to data.frame
pl_df <- data.frame(t(expr_mat)) %>%
rownames_to_column("Nhood") %>%
mutate(Nhood=as.double(Nhood)) %>%
left_join(da.res, by="Nhood") %>%
mutate(logFC_rank=percent_rank(logFC))
## Top plot: nhoods ranked by DA log FC
pl_top <- pl_df %>%
mutate(is_signif = ifelse(SpatialFDR < alpha, paste0("SpatialFDR < ", alpha), NA)) %>%
ggplot(aes(logFC_rank, logFC)) +
geom_hline(yintercept = 0, linetype=2) +
geom_point(size=0.2, color="grey") +
geom_point(data=. %>% dplyr::filter(!is.na(is_signif)), aes(color=is_signif), size=1) +
theme_bw(base_size=22) +
ylab("DA logFC") +
scale_color_manual(values="red", name="") +
guides(color=guide_legend(override.aes = list(size=2))) +
scale_x_continuous(expand = c(0.01, 0)) +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.title.x = element_blank())
## Bottom plot: gene expression heatmap
if (isTRUE(cluster_features)) {
row.order <- hclust(dist(expr_mat))$order # clustering
ordered_features <- rownames(expr_mat)[row.order]
} else {
ordered_features <- rownames(expr_mat)
}
# detach('package:EnsDb.Hsapiens.v86')
# detach('package:ensembldb')
highlight_genes <- c("PLVAP", "SOX14", "VWA1", "ACKR1",
"CLEC4G", "CLEC4M", "STAB2", "MRC1",
"CD14", "CCL21", "SOX17", "WNT2", "RSPO3", "AIF1L",
"PROX1", "PDPN","CPE", "CD320")
pl_bottom <- pl_df %>%
pivot_longer(cols=rownames(expr_mat), names_to='feature', values_to="avg_expr") %>%
mutate(feature=factor(feature, levels=ordered_features)) %>%
mutate(label=ifelse(feature %in% highlight_genes, as.character(feature), NA)) %>%
ggplot(aes(logFC_rank, feature, fill=avg_expr)) +
geom_tile() +
scale_fill_viridis_c(option="magma", name="Scaled \nexpression") +
xlab("Endothelial Neighbourhoods") + ylab("DE genes") +
scale_x_continuous(expand = c(0.01, 0),
# limits = c(0, max(pl_df$logFC_rank) + 0.2)
) +
coord_cartesian(clip="off") +
ggrepel::geom_text_repel(data=. %>% dplyr::filter(!is.na(label)) %>%
group_by(label) %>%
summarise(logFC_rank=max(logFC_rank), avg_expr=mean(avg_expr), feature=dplyr::first(feature)),
aes(label=label, x=logFC_rank), size=7, xlim = c(max(pl_df$logFC_rank) + 0.01, max(pl_df$logFC_rank) + 0.02),
min.segment.length = 0, seed=42
) +
theme_classic(base_size = 22) +
theme(axis.text.x = element_blank(), axis.line.x = element_blank(), axis.ticks.x = element_blank(),
axis.text.y = element_blank(), axis.line.y = element_blank(), axis.ticks.y = element_blank(),
panel.spacing = margin(2, 2, 2, 2, "cm"),
legend.margin=margin(0,0,0,0),
legend.box.margin=margin(10,10,10,10)
)
## Assemble plot
fig4_bbright <- (pl_top / pl_bottom) + plot_layout(heights = c(1,4), guides = "collect") &
theme(legend.justification=c(0, 1))
fig4_bbright + ggsave("~/milo_output/liver_DEG_heatmap.pdf", width=9, height = 9)

Quick GO term analysis
# install.packages("enrichR")
library(enrichR)
dbs <- listEnrichrDbs()
websiteLive <- TRUE
if (is.null(dbs)) websiteLive <- FALSE
if (websiteLive) head(dbs)
dbs <- c("GO_Molecular_Function_2015", "GO_Cellular_Component_2015", "GO_Biological_Process_2015")
go_marker_genes <- enrichr(marker_genes, dbs)
go_all_genes <- enrichr(endo_hvgs, dbs)
ref_terms <- go_all_genes$GO_Biological_Process_2015$Term[go_all_genes$GO_Biological_Process_2015$Adjusted.P.value < 0.01]
go_plot <- go_marker_genes$GO_Biological_Process_2015[go_marker_genes$GO_Biological_Process_2015$Adjusted.P.value < 0.01,] %>%
dplyr::filter(!Term %in% ref_terms) %>%
top_n(30, -log10(Adjusted.P.value)) %>%
mutate(Term=factor(Term, levels=rev(unique(Term)))) %>%
ggplot(aes(Term, -log10(Adjusted.P.value))) +
geom_point() +
coord_flip() +
xlab("GO Biological Function") + ylab("-log10(Adj. p-value)") +
theme_bw(base_size=14)
go_plot +
ggsave("~/milo_output/liver_endoDEG_GOenrich.pdf", width=9, height = 5)
Assemble figure
fig4_top /
((fig4_bleft | (fig4_bright1 / fig4_bbright) + plot_layout(heights = c(1,1.5))) +
plot_layout(widths=c(1,1.2))) +
plot_layout(heights=c(1,1.5)) +
ggsave("~/milo_output/fig4.pdf", height = 26, width = 22, useDingbats=FALSE)

NA
Assemble supplementary figure

Ci0tLQp0aXRsZTogIk1pbG86IGxpdmVyIGNpcnJob3NpcyBhbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIG5vdGVib29rIHdlIGRlbW9uc3RyYXRlIGhvdyB0byB1c2UgTWlsbyB0byBkZXRlY3QgYWJoZXJyYW50IGNlbGwgc3RhdGVzIGluIGRpc2Vhc2VkIHRpc3N1ZXMsIHVzaW5nIGEgZGF0YXNldCBvZiBoZXBhdGljIG5vbi1wYXJlbmNoeW1hbCBjZWxscyBpc29sYXRlZCBmcm9tIDUgaGVhbHRoeSBhbmQgNSBjaXJyaG90aWMgaHVtYW4gbGl2ZXJzLiBbUmFtYWNoYW5kcmFuIGV0IGFsLiAyMDE5XShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTU4Ni0wMTktMTYzMS0zI1NlYzEpIChHRU8gYWNjZXNzaWlvbjogR1NFMTM2MTAzKS4KCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoaXJsYmEpCiAgbGlicmFyeShEcm9wbGV0VXRpbHMpCiAgbGlicmFyeShzY2F0ZXIpCiAgbGlicmFyeShzY3JhbikKICBsaWJyYXJ5KFNldXJhdCkgIyMganVzdCA0IGxvYWRpbmcgdGhlIG9iamVjdAogIGxpYnJhcnkobWlsb1IpCiAgbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKICBsaWJyYXJ5KHBhdGNod29yaykKICBsaWJyYXJ5KGlncmFwaCkKICB9KQpgYGAKCiMjIExvYWQgZGF0YQoKV2UgZG93bmxvYWRlZCB0aGUgZGF0YXNldCBhbmQgYW5ub3RhdGlvbnMgc3RvcmVkIGluIFNldXJhdCBvYmplY3QgZnJvbSBbaGVyZV0oaHR0cHM6Ly9kYXRhc2hhcmUuaXMuZWQuYWMudWsvaGFuZGxlLzEwMjgzLzM0MzMpLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIGF1dGhvcnMuCgpgYGB7cn0KbG9hZCgiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvdGlzc3VlLnJkYXRhIikKCiMjIENvbnZlcnQgdG8gU2luZ2xlQ2VsbEV4cGVyaW1lbnQKbGl2ZXJfc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGFzc2F5ID0gbGlzdChjb3VudHM9dGlzc3VlQHJhdy5kYXRhLCBsb2djb3VudHM9dGlzc3VlQGRhdGEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSB0aXNzdWVAbWV0YS5kYXRhKQoKbGl2ZXJfc2NlCmBgYAoKIyMgUHJlcHJvY2Vzc2luZyAKCiMjIyBGZWF0dXJlIHNlbGVjdGlvbgoKYGBge3J9CmRlY19saXZlciA8LSBtb2RlbEdlbmVWYXIobGl2ZXJfc2NlKQoKZml0X2xpdmVyIDwtIG1ldGFkYXRhKGRlY19saXZlcikKcGxvdChmaXRfbGl2ZXIkbWVhbiwgZml0X2xpdmVyJHZhciwgeGxhYj0iTWVhbiBvZiBsb2ctZXhwcmVzc2lvbiIsCiAgICB5bGFiPSJWYXJpYW5jZSBvZiBsb2ctZXhwcmVzc2lvbiIpCgpodmdzIDwtIGdldFRvcEhWR3MoZGVjX2xpdmVyLCBuPTMwMDApCmBgYAoKIyMjIERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB3aXRoIFBDQQoKYGBge3IsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xNH0KbGl2ZXJfc2NlIDwtIHJ1blBDQShsaXZlcl9zY2UsIHN1YnNldF9yb3c9aHZncywgbmNvbXBvbmVudHM9MTEpCgpwbG90UENBKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJjb25kaXRpb24iLCBuY29tcG9uZW50cz0zKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpsaXZlcl9zY2UgPC0gcnVuVU1BUChsaXZlcl9zY2UsIGRpbXJlZD0iUENBIiwgbmNvbXBvbmVudHM9MikKCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImNvbmRpdGlvbiIsIHBvaW50X2FscGhhPTEsICBwb2ludF9zaXplPTAuNSkgCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImRhdGFzZXQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkKc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iYW5ub3RhdGlvbl9saW5lYWdlIiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25fbGluZWFnZScpCiMgc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0nYW5ub3RhdGlvbl9pbmRlcHRoJywgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25faW5kZXB0aCcpCmBgYAoKTm90YWJseSwgdGhpcyBkYXRhc2V0IGRvZXNuJ3QgYXBwZWFyIHRvIGRpc3BsYXkgYSBiYXRjaCBlZmZlY3QKCiMjIERBIGFuYWx5c2lzIHdpdGggTWlsbwoKV2UgdGVzdCBmb3IgZGlmZmVyZW50aWFsIGFidW5kYW5jZSBiZXR3ZWVuIGhlYWx0aHkgYW5kIGNpcnJob3RpYyBsaXZlcnMuIFdlIHN0YXJ0IGJ5IGRlZmluaW5nIG5laWdoYm91cmhvb2RzIHdpdGggcmVmaW5lZCBzYW1wbGluZyBvbiB0aGUgS05OIGdyYXBoLiBXZSBpbnNwZWN0IHRoZSBzaXplIG9mIG5laWdoYm91cmhvb2RzLgoKYGBge3J9CmxpdmVyX21pbG8gPC0gTWlsbyhsaXZlcl9zY2UpCgojIyBCdWlsZCBLTk4gZ3JhcGgKbGl2ZXJfbWlsbyA8LSBidWlsZEdyYXBoKGxpdmVyX21pbG8sIGQgPSAxMSwgaz0zMCkKCiMjIENvbXB1dGUgbmVpZ2hib3VyaG9vZHMgd2l0aCByZWZpbmVkIHNhbXBsaW5nCmxpdmVyX21pbG8gPC0gbWFrZU5ob29kcyhsaXZlcl9taWxvLCBrPTMwLCBkPTExLCBwcm9wID0gMC4wNSwgcmVmaW5lZD1UUlVFKQpwbG90Tmhvb2RTaXplSGlzdChsaXZlcl9taWxvLCBiaW5zPTE1MCkKYGBgCgpUaGVuIHdlIG1ha2UgYSBkZXNpZ24gbWF0cml4IGZvciB0aGUgZGlmZmVyZW50aWFsIHRlc3QsIGFzc2lnbmluZyBzYW1wbGVzIHRvIGNvbmRpdGlvbnMuCgpgYGB7cn0KbGl2ZXJfbWV0YSA8LSBhcy50aWJibGUoY29sRGF0YShsaXZlcl9taWxvKVssYygiZGF0YXNldCIsImNvbmRpdGlvbiIpXSkgCmxpdmVyX21ldGEgPC0gZGlzdGluY3QobGl2ZXJfbWV0YSkgJT4lCiAgbXV0YXRlKGNvbmRpdGlvbj1mYWN0b3IoY29uZGl0aW9uLCBsZXZlbHM9YygiVW5pbmp1cmVkIiwgIkNpcnJob3RpYyIpKSkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJkYXRhc2V0IikKYGBgCgpOb3cgd2UgY2FuIGNvdW50IGNlbGxzIGluIG5laWdoYm91cmhvb2RzIGFuZCBwZXJmb3JtIHRoZSBEQSB0ZXN0LgoKYGBge3J9CmxpdmVyX21pbG8gPC0gY291bnRDZWxscyhsaXZlcl9taWxvLCBzYW1wbGVzID0gImRhdGFzZXQiLCBtZXRhLmRhdGEgPSBkYXRhLmZyYW1lKGNvbERhdGEobGl2ZXJfbWlsbylbLGMoImRhdGFzZXQiLCJjb25kaXRpb24iKV0pICkKCmxpdmVyX21pbG8gPC0gY2FsY05ob29kRGlzdGFuY2UobGl2ZXJfbWlsbywgZD0xMSkKbWlsb19yZXMgPC0gdGVzdE5ob29kcyhsaXZlcl9taWxvLCBkZXNpZ24gPSB+IGNvbmRpdGlvbiwgZGVzaWduLmRmID0gbGl2ZXJfbWV0YSwgZmRyLndlaWdodGluZyA9ICJrLWRpc3RhbmNlIikKYGBgCgpgYGB7cn0KIyMgU2F2ZSBtaWxvIG9iamVjdCBhbmQgcmVzdWx0cwpzYXZlUkRTKGxpdmVyX21pbG8sIi9uZnMvdGVhbTIwNS9lZDYvZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL3Rpc3N1ZV9taWxvLlJEUyIpCnNhdmVSRFMobGl2ZXJfbWlsbywifi9saXZlcl9taWxvXzIwMjAxMDA4LlJEUyIpCndyaXRlX2NzdihtaWxvX3JlcywgIi9uZnMvdGVhbTIwNS9lZDYvZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL21pbG9fcmVzdWx0cy5jc3YiKQp3cml0ZV9jc3YobWlsb19yZXMsIi9uZnMvdGVhbTIwNS9lZDYvZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL2xpdmVyX3Jlc3VsdHNfMjAyMDEwMDguY3N2IikKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpsaXZlcl9taWxvIDwtIHJlYWRSRFMoIn4vbGl2ZXJfbWlsb18yMDIwMTAwOC5SRFMiKQptaWxvX3JlcyA8LSByZWFkX2Nzdigifi9saXZlcl9yZXN1bHRzXzIwMjAxMDA4LmNzdiIpCmBgYAoKIyMgRXhwbG9yYXRpb24gb2YgREEgcmVzdWx0cwoKV2UgY2FuIHN0YXJ0IGJ5IGxvb2tpbmcgYXQgc29tZSBiYXNpYyBzdGF0cwoKYGBge3J9CnB2YWxfaGlzdCA8LSBtaWxvX3JlcyAlPiUKICBnZ3Bsb3QoYWVzKFBWYWx1ZSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz01MCkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNCkKCnZvbGNhbm8gPC0gCiAgbWlsb19yZXMgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQywgLWxvZzEwKFNwYXRpYWxGRFIpKSkgKyAKICBnZW9tX3BvaW50KHNpemU9MC40LCBhbHBoYT0wLjIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4xKSkgKwogIHhsYWIoImxvZy1Gb2xkIENoYW5nZSIpICsKICB0aGVtZV9idyhiYXNlX3NpemU9MTQpCgpwdmFsX2hpc3QgKyB2b2xjYW5vCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBQLXZhbHVlcyBsb29rcyBzZW5zaWJsZSBhbmQgZnJvbSB0aGUgdm9sY2FubyBwbG90IHdlIGNhbiBzZWUgdGhhdCB3ZSBoYXZlIGlkZW50aWZpZWQgc29tZSBEQSBuZWlnaGJvdXJob29kcyBhdCAxMCUgRkRSLgpXZSBjYW4gdmlzdWFsaXplIERBIG5laWdoYm91cmhvb2RzIGJ1aWxkaW5nIGFuIGFic3RyYWN0ZWQgZ3JhcGgKCmBgYHtyLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTB9CmxpdmVyX21pbG8gPC0gYnVpbGROaG9vZEdyYXBoKGxpdmVyX21pbG8pCnBsb3ROaG9vZEdyYXBoREEobGl2ZXJfbWlsbywgbWlsb19yZXMsIGFscGhhID0gMC4wNSkKYGBgCgpNYWtpbmcgZmlndXJlcyBmb3IgdGhlIG1hbnVzY3JpcHQKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTB9CmNvbG91ckNvdW50ID0gbGVuZ3RoKHVuaXF1ZShsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZSkpCmdldFBhbGV0dGUgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwgIlNwZWN0cmFsIikpCgp1bWFwX2RmIDwtIGRhdGEuZnJhbWUocmVkdWNlZERpbShsaXZlcl9taWxvLCAiVU1BUCIpKQpjb2xuYW1lcyh1bWFwX2RmKSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikKCnVtYXAxIDwtIGNiaW5kKHVtYXBfZGYsIGFubm90YXRpb25fbGluZWFnZT1saXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZSkgJT4lCiAgZ2dwbG90KGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3I9YXMuY2hhcmFjdGVyKGFubm90YXRpb25fbGluZWFnZSkpKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMSwgYWxwaGE9MC41KSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSAuICU+JSAKICAgICAgICAgICAgICBncm91cF9ieShhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JSAKICAgICAgICAgICAgICBzdW1tYXJpc2UoVU1BUF8xPW1lYW4oVU1BUF8xKSwgVU1BUF8yPW1lYW4oVU1BUF8yKSksCiAgICAgICAgICAgIGFlcyhsYWJlbD1hbm5vdGF0aW9uX2xpbmVhZ2UpLCBjb2xvcj0iYmxhY2siLCBzaXplPTYKICAgICAgICAgICAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1nZXRQYWxldHRlKGNvbG91ckNvdW50KSkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICB4bGFiKCJVTUFQMSIpICsgeWxhYigiVU1BUDIiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAyMikgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE4KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQoKdW1hcDIgPC0KICBjYmluZCh1bWFwX2RmLCBjb25kaXRpb249YXMuY2hhcmFjdGVyKGxpdmVyX21pbG8kY29uZGl0aW9uKSkgJT4lCiAgZ2dwbG90KGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3I9Y29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0wLjEsIGFscGhhPTAuNSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIiwgbmFtZT0nJykgKwogIHhsYWIoIlVNQVAxIikgKyB5bGFiKCJVTUFQMiIpICsKICBjb29yZF9maXhlZCgpICsKICBndWlkZXMoY29sb3I9J25vbmUnKSArCiAgZmFjZXRfd3JhcChjb25kaXRpb25+LiwgbmNvbD0xKSArCiAgdGhlbWVfbm90aGluZygpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9TkEpLCBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpKQoKbmhfZ3JhcGhfcGwgPC0gcGxvdE5ob29kR3JhcGhEQShsaXZlcl9taWxvLCBtaWxvX3JlcywgYWxwaGEgPSAwLjEpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjQpKSArCiAgY29vcmRfZml4ZWQoKQoKZmlnNF90b3AgPC0gKHVtYXAxIHwgdW1hcDIgfCBuaF9ncmFwaF9wbCkgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDMsMSwzKSkgCgpmaWc0X3RvcCArCiAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VtYmVkZGluZy5wZGYiLCB3aWR0aD0xNSwgaGVpZ2h0ID0gMTApCmBgYAoKTmV4dCwgd2UgY2FuIGNoZWNrIHRoZSBjZWxsIHR5cGVzIHdoZXJlIHdlIG9ic2VydmUgbW9zdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIGhlYWx0aHkgYW5kIGNpcnJob3RpYyBjZWxscywgYnkgdGFraW5nIHRoZSBtb3N0IGZyZXF1ZW50IGNlbGwgdHlwZSBpbiBlYWNoIG5laWdoYm91cmhvb2QuCgpgYGB7ciwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9MTB9CiMnIEFkZCBhbm5vdGF0aW9uIG9mIG1vc3QgZnJlcXVlbnQgY2VsbCB0eXBlIHBlciBuaG9vZCB0byBtaWxvIHJlc3VsdHMgdGFibGUKYWRkX25ob29kX2NvbGRhdGFfdG9fcmVzIDwtIGZ1bmN0aW9uKG1pbG8sIG1pbG9fcmVzLCBjb2xkYXRhX2NvbCl7CiAgbmhvb2RfY291bnRzIDwtIHNhcHBseShzZXFfYWxvbmcobmhvb2RzKG1pbG8pKSwgZnVuY3Rpb24oeCkgdGFibGUoY29sRGF0YShtaWxvKVthcy52ZWN0b3Iobmhvb2RzKG1pbG8pW1t4XV0pLCBjb2xkYXRhX2NvbF0pKQogIG5ob29kX2NvdW50cyA8LSB0KG5ob29kX2NvdW50cykKICByb3duYW1lcyhuaG9vZF9jb3VudHMpIDwtIHNlcV9hbG9uZyhuaG9vZHMobWlsbykpCiAgbWF4X3ZhbCA8LSBhcHBseShuaG9vZF9jb3VudHMsIDEsIGZ1bmN0aW9uKHgpIGNvbG5hbWVzKG5ob29kX2NvdW50cylbd2hpY2gubWF4KHgpXSkKICBtYXhfZnJhYyA8LSBhcHBseShuaG9vZF9jb3VudHMsIDEsIGZ1bmN0aW9uKHgpIG1heCh4KS9zdW0oeCkpCiAgbWlsb19yZXNbY29sZGF0YV9jb2xdIDwtIG1heF92YWwKICBtaWxvX3Jlc1twYXN0ZTAoY29sZGF0YV9jb2wsICJfZnJhY3Rpb24iKV0gPC0gbWF4X2ZyYWMKICByZXR1cm4obWlsb19yZXMpCn0KCm1pbG9fcmVzIDwtIGFkZF9uaG9vZF9jb2xkYXRhX3RvX3JlcyhsaXZlcl9taWxvLCBtaWxvX3JlcywgImFubm90YXRpb25faW5kZXB0aCIpCm1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZS54IDwtIE5VTEwKbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlLnkgPC0gTlVMTAptaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2UgPC0gTlVMTAphbm5vX2RmIDwtIGRhdGEuZnJhbWUobGl2ZXJfbWlsb0Bjb2xEYXRhKSAlPiUKICBkaXN0aW5jdChhbm5vdGF0aW9uX2xpbmVhZ2UsIGFubm90YXRpb25faW5kZXB0aCkKbWlsb19yZXMgPC0gbGVmdF9qb2luKG1pbG9fcmVzLCBhbm5vX2RmLCBieT0iYW5ub3RhdGlvbl9pbmRlcHRoIikKYGBgCgpXZSBmaXJzdCBjaGVjayB0aGF0IG5laWdoYm91cmhvb2RzIGFyZSBxdWl0ZSBob21vZ2VuZW91cwoKYGBge3J9CmZyYWNfaGlzdCA8LSBnZ3Bsb3QobWlsb19yZXMsIGFlcyhhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0zMCkgKwogIHhsYWIoIkZyYWN0aW9uIG9mIGNlbGxzIGluIFxubW9zdCBhYnVuZGFudCBjbHVzdGVyIikgKwogIHlsYWIoIiMgbmVpZ2hib3VyaG9vZHMiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KQoKZnJhY19oaXN0CmBgYAoKSSBjYW4gcmVjb3ZlciBhbGwgdGhlIGNsdXN0ZXJzIHdoZXJlIERBIHdhcyBkZXRlY3RlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXIgKHNlZSBhbGwgdGhlIGJhcnBsb3RzIGZvciBlYWNoIGxpbmVhZ2UpIGFuZCBtb3JlISBBbGwgaW4gYSBzaW5nbGUgYW5hbHlzaXMsIGFuZCB3aXRob3V0IGtub3dpbmcgd2hlcmUgdGhlIHN1YmNsdXN0ZXJzIGFyZS4gTGV0J3MgYmVhciBpbiBtaW5kIHRoYXQgcG9zaXRpdmUgbG9nRkMgLS0+IG1vcmUgY2lycmhvdGljLCBuZWdhdGl2ZSBsb2dGQyAtLS0+IG1vcmUgaGVhbHRoeQoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KcGFwZXJfREEgPC0gbGlzdChjaXJyaG90aWM9YygiTVBzICg0KSIsIk1QcyAoNSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhICg2KSIsICJFbmRvdGhlbGlhICg3KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lcyAoMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUY2VsbHMgKDIpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXlvZmlicm9ibGFzdHMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICBoZWFsdGh5PWMoIk1QcyAoNykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYSAoMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGNlbGxzICgxKSIsICJUY2VsbHMgKDMpIiwiVGNlbGxzICgxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJJTENzICgxKSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICkKCmV4cERBX2RmIDwtIGJpbmRfcm93cygKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siY2lycmhvdGljIl1dLCBwcmVkX0RBPSJjaXJyaG90aWMiKSwKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siaGVhbHRoeSJdXSwgcHJlZF9EQT0iaGVhbHRoeSIpCiAgKQoKcGwxIDwtIG1pbG9fcmVzICU+JQogIGxlZnRfam9pbihleHBEQV9kZikgJT4lCiAgbXV0YXRlKGlzX3NpZ25pZiA9IGlmZWxzZShTcGF0aWFsRkRSIDwgMC4xLCAxLCAwKSkgJT4lCiAgbXV0YXRlKGxvZ0ZDX2NvbG9yID0gaWZlbHNlKGlzX3NpZ25pZj09MSwgbG9nRkMsIE5BKSkgJT4lCiAgYXJyYW5nZShhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JQogIG11dGF0ZShOaG9vZD1mYWN0b3IoTmhvb2QsIGxldmVscz11bmlxdWUoTmhvb2QpKSkgJT4lCiAgZ2dwbG90KGFlcyhhbm5vdGF0aW9uX2luZGVwdGgsIGxvZ0ZDLCBjb2xvcj1sb2dGQ19jb2xvcikpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIoKSArCiAgZ3VpZGVzKGNvbG9yPSJub25lIikgKwogIHhsYWIoImFubm90YXRpb24iKSArIHlsYWIoIkxvZyBGb2xkIENoYW5nZSIpICsKICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKGFscGhhPTEpICsKICBjb29yZF9mbGlwKCkgKwogIGZhY2V0X2dyaWQoYW5ub3RhdGlvbl9saW5lYWdlfi4sIHNjYWxlcz0iZnJlZSIsIHNwYWNlPSJmcmVlIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0yMikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9ICBlbGVtZW50X3RleHQoYW5nbGU9MCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICkKCnBsMiA8LSBtaWxvX3JlcyAlPiUKICBsZWZ0X2pvaW4oZXhwREFfZGYpICU+JQogICMgZHBseXI6OmZpbHRlcighaXMubmEocHJlZF9EQSkpICU+JQogIGdyb3VwX2J5KGFubm90YXRpb25faW5kZXB0aCkgJT4lCiAgc3VtbWFyaXNlKHByZWRfREE9ZHBseXI6OmZpcnN0KHByZWRfREEpLCBhbm5vdGF0aW9uX2xpbmVhZ2U9ZHBseXI6OmZpcnN0KGFubm90YXRpb25fbGluZWFnZSkpICU+JQogIG11dGF0ZShlbmQ9aWZlbHNlKHByZWRfREE9PSJoZWFsdGh5IiwgMCwgMSksCiAgICAgICAgIHN0YXJ0PWlmZWxzZShwcmVkX0RBPT0iaGVhbHRoeSIsIDEsIDApKSAlPiUKICBnZ3Bsb3QoYWVzKGFubm90YXRpb25faW5kZXB0aCwgc3RhcnQsIHhlbmQgPSBhbm5vdGF0aW9uX2luZGVwdGgsIHllbmQgPSBlbmQsIGNvbG9yPXByZWRfREEpKSArCiAgZ2VvbV9zZWdtZW50KHNpemU9MSxhcnJvdz1hcnJvdyhsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpLCB0eXBlPSJjbG9zZWQiKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiYW5ub3RhdGlvbiIpICsKICBmYWNldF9ncmlkKGFubm90YXRpb25fbGluZWFnZX4uLAogICAgIyBhbm5vdGF0aW9uX2xpbmVhZ2V+IlJhbWFjaGFuZHJhbiBldCBhbC5cbkRBIHByZWRpY3Rpb25zIiwgCiAgICAgICAgICAgICBzY2FsZXM9ImZyZWUiLCBzcGFjZT0iZnJlZSIpICsKICAjIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIGRpcmVjdGlvbiA9IC0xLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoImVucmljaGVkIGluIGNpcnJob3RpYyIsICJlbnJpY2hlZCBpbiBoZWFsdGh5IiksCiAgICAgICAgICAgICAgICAgICAgIG5hLnRyYW5zbGF0ZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlJhbWFjaGFuZHJhbiBldCBhbC5cbkRBIHByZWRpY3Rpb25zIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobmNvbCA9IDEpKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTIyKSArCiAgeWxpbSgtMC4xLDEuMSkgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLDApLCAiY20iKSwgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpmaWc0X2JsZWZ0IDwtIChwbDIgKyBwbDEgKyAKICBwbG90X2xheW91dCh3aWR0aHM9YygxLDEwKSwgZ3VpZGVzID0gImNvbGxlY3QiKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICd0b3AnLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IDApKSAKCmZpZzRfYmxlZnQgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9saXZlcl9EQWNvbXBhcmlzb24ucGRmIiwgd2lkdGg9OCwgaGVpZ2h0ID0gMTMpCmBgYAoKIyMgQ2xvc2UtdXAgb24gRW5kb3RoZWxpYWwgbGluZWFnZQoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQojIGVuZG9fbWlsbyA8LSBzY2F0ZXI6OnJ1blBDQShlbmRvX21pbG8sIHN1YnNldF9yb3c9ZW5kb19odmdzLCBuY29tcG9uZW50cz0xMSkKZW5kb19taWxvIDwtIHNjYXRlcjo6cnVuVU1BUChsaXZlcl9taWxvWyxsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiXSwgIGRpbXJlZD0nUENBJykKCnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgplbmRvX3VtYXAgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWVuZG9fbWlsbyRjb25kaXRpb24pICU+JQogICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMywgYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lPScnKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBmYWNldF93cmFwKGNvbmRpdGlvbn4uLCBuY29sPTEpICsKICB0aGVtZV9ub3RoaW5nKCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPWMoMC45LDAuOSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj1OQSksIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNikpCgplbmRvX3VtYXAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0KbGl2ZXJfbWlsbzIgPC0gbGl2ZXJfbWlsbwpzdWJzZXQubmhvb2RzIDwtIHN0cl9kZXRlY3QobWlsb19yZXMkYW5ub3RhdGlvbl9pbmRlcHRoLCAiRW5kbyIpCnJlZHVjZWREaW0obGl2ZXJfbWlsbzIsICJVTUFQIilbY29sbmFtZXMoZW5kb19taWxvKSxdIDwtIHJlZHVjZWREaW0oZW5kb19taWxvLCAiVU1BUCIpIAoKCmVuZG9fZ3IgPC0KICBwbG90Tmhvb2RHcmFwaERBKAogIGxpdmVyX21pbG8yLCBtaWxvX3JlcywKICBzdWJzZXQubmhvb2RzID0gc3Vic2V0Lm5ob29kcywgCiAgIyBzdWJzZXQubmhvb2RzID1zdWJzZXQubmhvb2RzWzE6KGxlbmd0aChzdWJzZXQubmhvb2RzKS0xKV0sIAogIGFscGhhID0gMC4xCiAgKSAgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjQpKQogIApmaWc0X2JyaWdodDEgPC0gKChlbmRvX3VtYXAgKyBlbmRvX2dyICkgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMiksIAogICAgICAgICAgICAgICAgZ3VpZGVzID0gImNvbGxlY3QiCiAgICAgICAgICAgICAgICApKSAKCmZpZzRfYnJpZ2h0MSArCiAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VuZG9HcmFwaC5wZGYiLCB3aWR0aD05LCBoZWlnaHQgPSA1KSAgCmBgYAoKCgojIyMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBEQSBuZWlnaGJvdXJob29kcwoKSSB3YW50IHRvIG1lcmdlIG92ZXJsYXBwaW5nIG5ob29kcyB3aXRoIHNpZ25pZmljYW50IERBIGFuZCB0aGUgc2FtZSBkaXJlY3Rpb24gb2YgbG9nRkMsIGFuZCB0aGVuIHRlc3QgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGJldHdlZW4gY2VsbHMgaW4gdXAgYW5kIGRvd24gbmhvb2RzIChJIGd1ZXNzIHlvdSBjb3VsZCBhbHNvIGRvIHVwIG9yIGRvd24gVlMgYWxsIHRoZSByZXN0KS4gVGhpcyBhbGxvd3MgdXMgdG8gcGVyZm9ybSBhIGNvbXBhcmlzb24gd2l0aG91dCBmdXJ0aGVyIGNsdXN0ZXJpbmcuCgpgYGB7cn0KZW5kb19taWxvIDwtIGxpdmVyX21pbG9bLHdoaWNoKGxpdmVyX21pbG8kYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpXQplbmRvX3JlcyA8LSBkcGx5cjo6ZmlsdGVyKG1pbG9fcmVzLCBhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIikKCnJvd25hbWVzKGVuZG9fcmVzKSA8LSByb3duYW1lcyhtaWxvX3Jlcylbd2hpY2gobWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpXQpgYGAKCgpgYGB7cn0KZGVjX2xpdmVyIDwtIG1vZGVsR2VuZVZhcihsaXZlcl9taWxvKQpmaXRfbGl2ZXIgPC0gbWV0YWRhdGEoZGVjX2xpdmVyKQpodmdzIDwtIGdldFRvcEhWR3MoZGVjX2xpdmVyLCBuPTMwMDApCgojIyBrZWVwIEhWIGdlbmVzIGV4cHJlc3NlZCBpbiBhdCBsZWFzdCA1JSBvZiBlbmRvdGhlbGlhbCBjZWxscwplbmRvX2h2Z19jbnRzIDwtIGNvdW50cyhsaXZlcl9taWxvKVtodmdzLGxpdmVyX21pbG8kYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSJdCmVuZG9faHZncyA8LSBodmdzWyhyb3dTdW1zKGVuZG9faHZnX2NudHMhPTApID4gKG5jb2woZW5kb19odmdfY250cykvMTAwKSo1KSAmIChyb3dTdW1zKGVuZG9faHZnX2NudHMhPTApIDwgKG5jb2woZW5kb19odmdfY250cykvMTAwKSo4MCldIApgYGAKCgoKYGBge3J9CiMgcm93bmFtZXMobWlsb19yZXMpIDwtIG5hbWVzKG5ob29kcyhsaXZlcl9taWxvKSkgIyMgSWYgSSBkb24ndCBzZXQgdGhlIG5ob29kIGluZGV4IGFzIG5hbWUgdGhlIGdyb3VwaW5nIGRvZXNuJ3QKbmhvb2RfbWFya2VycyA8LSBmaW5kTmhvb2RNYXJrZXJzKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBvdmVybGFwPTEsIGFzc2F5PSJsb2djb3VudHMiLCByZXR1cm4uZ3JvdXBzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5yb3cgPSBlbmRvX2h2Z3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gc3RyX2RldGVjdChtaWxvX3JlcyRhbm5vdGF0aW9uX2luZGVwdGgsICJFbmRvIikpCgoKc3VtKG5ob29kX21hcmtlcnMkZGdlJGFkai5QLlZhbF8xIDwgMC4wMSkKYGBgCgpgYGB7cn0KbWFya2VyX2dlbmVzIDwtIG5ob29kX21hcmtlcnMkZGdlICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsXzEgPCAwLjAxKSAlPiUKICBwdWxsKEdlbmVJRCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xOCwgZmlnLndpZHRoPTEyfQpsaXZlcl9taWxvIDwtIGNhbGNOaG9vZEV4cHJlc3Npb24obGl2ZXJfbWlsbywgc3Vic2V0LnJvdyA9IG1hcmtlcl9nZW5lcykKCmhpZ2hsaWdodF9nZW5lcyA8LSBjKCJQTFZBUCIsICJTT1gxNCIsICJWV0ExIiwgIkFDS1IxIiwKICAgICAgICAgICAgICAgICAgICAgIkNMRUM0RyIsICJDTEVDNE0iLCAiU1RBQjIiLCAiTVJDMSIsCiAgICAgICAgICAgICAgICAgICAgICJDRDE0IiwgIkNDTDIxIiwgIlNPWDE3IiwgIldOVDIiLCAiUlNQTzMiLCAiQUlGMUwiLAogICAgICAgICAgICAgICAgICAgICAiUFJPWDEiLCAiUERQTiIsIkNQRSIsICJDRDMyMCIpCgpmaWc0X2JicmlnaHQgPC0gcGxvdE5ob29kRXhwcmVzc2lvbkRBKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBtYXJrZXJfZ2VuZXMsIGNsdXN0ZXJfZmVhdHVyZXMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xLAogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfdG9fMSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdobGlnaHRfZmVhdHVyZXMgPSBoaWdobGlnaHRfZ2VuZXMsIHNob3dfcm93bmFtZXMgPSBGQUxTRQogICAgICAgICAgICAgICAgICAgICAgKSArCiAgeWxhYigiREUgZ2VuZXMiKSArCiAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yNCkpCmBgYAoKCkN1c3RvbWl6ZSBwbG90dGluZyBmb3IgcGFwZXIgZmlndXJlCgpgYGB7cn0KeCA8LSBsaXZlcl9taWxvCmRhLnJlcyA8LSBtaWxvX3JlcwoKY2x1c3Rlcl9mZWF0dXJlcyA9IFRSVUUKYWxwaGEgPSAwLjEKc2NhbGVfdG9fMSA9IFRSVUUKc3Vic2V0Lm5ob29kcyA9IG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiCmZlYXR1cmVzIDwtIG1hcmtlcl9nZW5lcwoKZXhwcl9tYXQgPC0gbmhvb2RFeHByZXNzaW9uKHgpW2ZlYXR1cmVzLF0KY29sbmFtZXMoZXhwcl9tYXQpIDwtIDE6bGVuZ3RoKG5ob29kcyh4KSkKCiMjIEdldCBuaG9vZCBleHByZXNzaW9uIG1hdHJpeAppZiAoIWlzLm51bGwoc3Vic2V0Lm5ob29kcykpIHsKICBleHByX21hdCA8LSBleHByX21hdFssc3Vic2V0Lm5ob29kcywgZHJvcD1GQUxTRV0KfQoKaWYgKCFpc0ZBTFNFKHNjYWxlX3RvXzEpKSB7CiAgZXhwcl9tYXQgPC0gdChhcHBseShleHByX21hdCwgMSwgZnVuY3Rpb24oeCkgKHggLSBtaW4oeCkpLyhtYXgoeCktIG1pbih4KSkpKQp9Cgpyb3duYW1lcyhleHByX21hdCkgPC0gc3ViKHBhdHRlcm4gPSAiLSIsIHJlcGxhY2VtZW50ID0gIi4iLCByb3duYW1lcyhleHByX21hdCkpICMjIFRvIGF2b2lkIHByb2JsZW1zIHdoZW4gY29udmVydGluZyB0byBkYXRhLmZyYW1lCgpwbF9kZiA8LSBkYXRhLmZyYW1lKHQoZXhwcl9tYXQpKSAlPiUKICByb3duYW1lc190b19jb2x1bW4oIk5ob29kIikgJT4lCiAgbXV0YXRlKE5ob29kPWFzLmRvdWJsZShOaG9vZCkpICU+JQogIGxlZnRfam9pbihkYS5yZXMsIGJ5PSJOaG9vZCIpICU+JQogIG11dGF0ZShsb2dGQ19yYW5rPXBlcmNlbnRfcmFuayhsb2dGQykpCgojIyBUb3AgcGxvdDogbmhvb2RzIHJhbmtlZCBieSBEQSBsb2cgRkMKcGxfdG9wIDwtIHBsX2RmICU+JQogIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IGFscGhhLCBwYXN0ZTAoIlNwYXRpYWxGRFIgPCAiLCBhbHBoYSksIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBsb2dGQykpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMiwgY29sb3I9ImdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhPS4gJT4lIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGlzX3NpZ25pZikpLCBhZXMoY29sb3I9aXNfc2lnbmlmKSwgc2l6ZT0xKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTIyKSArCiAgeWxhYigiREEgbG9nRkMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0icmVkIiwgbmFtZT0iIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTIpKSkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMDEsIDApKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKIyMgQm90dG9tIHBsb3Q6IGdlbmUgZXhwcmVzc2lvbiBoZWF0bWFwCmlmIChpc1RSVUUoY2x1c3Rlcl9mZWF0dXJlcykpIHsKICByb3cub3JkZXIgPC0gaGNsdXN0KGRpc3QoZXhwcl9tYXQpKSRvcmRlciAjIGNsdXN0ZXJpbmcKICBvcmRlcmVkX2ZlYXR1cmVzIDwtIHJvd25hbWVzKGV4cHJfbWF0KVtyb3cub3JkZXJdCn0gZWxzZSB7CiAgb3JkZXJlZF9mZWF0dXJlcyA8LSByb3duYW1lcyhleHByX21hdCkKfQoKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTB9CiMgZGV0YWNoKCdwYWNrYWdlOkVuc0RiLkhzYXBpZW5zLnY4NicpCiMgZGV0YWNoKCdwYWNrYWdlOmVuc2VtYmxkYicpCgpoaWdobGlnaHRfZ2VuZXMgPC0gYygiUExWQVAiLCAiU09YMTQiLCAiVldBMSIsICJBQ0tSMSIsCiAgICAgICAgICAgICAgICAgICAgICJDTEVDNEciLCAiQ0xFQzRNIiwgIlNUQUIyIiwgIk1SQzEiLAogICAgICAgICAgICAgICAgICAgICAiQ0QxNCIsICJDQ0wyMSIsICJTT1gxNyIsICJXTlQyIiwgIlJTUE8zIiwgIkFJRjFMIiwKICAgICAgICAgICAgICAgICAgICAgIlBST1gxIiwgIlBEUE4iLCJDUEUiLCAiQ0QzMjAiKQoKcGxfYm90dG9tIDwtIHBsX2RmICU+JQogIHBpdm90X2xvbmdlcihjb2xzPXJvd25hbWVzKGV4cHJfbWF0KSwgbmFtZXNfdG89J2ZlYXR1cmUnLCB2YWx1ZXNfdG89ImF2Z19leHByIikgJT4lCiAgbXV0YXRlKGZlYXR1cmU9ZmFjdG9yKGZlYXR1cmUsIGxldmVscz1vcmRlcmVkX2ZlYXR1cmVzKSkgJT4lCiAgbXV0YXRlKGxhYmVsPWlmZWxzZShmZWF0dXJlICVpbiUgaGlnaGxpZ2h0X2dlbmVzLCBhcy5jaGFyYWN0ZXIoZmVhdHVyZSksIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBmZWF0dXJlLCBmaWxsPWF2Z19leHByKSkgKwogIGdlb21fdGlsZSgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249Im1hZ21hIiwgbmFtZT0iU2NhbGVkIFxuZXhwcmVzc2lvbiIpICsKICB4bGFiKCJFbmRvdGhlbGlhbCBOZWlnaGJvdXJob29kcyIpICsgeWxhYigiREUgZ2VuZXMiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4wMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLCBtYXgocGxfZGYkbG9nRkNfcmFuaykgKyAwLjIpCiAgICAgICAgICAgICAgICAgICAgICkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwPSJvZmYiKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGE9LiAlPiUgZHBseXI6OmZpbHRlcighaXMubmEobGFiZWwpKSAlPiUKICAgICAgICAgICAgICBncm91cF9ieShsYWJlbCkgJT4lCiAgICAgICAgICAgICAgc3VtbWFyaXNlKGxvZ0ZDX3Jhbms9bWF4KGxvZ0ZDX3JhbmspLCBhdmdfZXhwcj1tZWFuKGF2Z19leHByKSwgZmVhdHVyZT1kcGx5cjo6Zmlyc3QoZmVhdHVyZSkpLAogICAgICAgICAgICBhZXMobGFiZWw9bGFiZWwsIHg9bG9nRkNfcmFuayksIHNpemU9NywgeGxpbSA9IGMobWF4KHBsX2RmJGxvZ0ZDX3JhbmspICsgMC4wMSwgbWF4KHBsX2RmJGxvZ0ZDX3JhbmspICsgMC4wMiksCiAgICAgICAgICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHNlZWQ9NDIKICAgICAgICAgICAgKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAyMikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLnNwYWNpbmcgPSBtYXJnaW4oMiwgMiwgMiwgMiwgImNtIiksCiAgICAgICAgbGVnZW5kLm1hcmdpbj1tYXJnaW4oMCwwLDAsMCksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW49bWFyZ2luKDEwLDEwLDEwLDEwKQogICAgICAgICkKCiMjIEFzc2VtYmxlIHBsb3QKZmlnNF9iYnJpZ2h0IDwtICAocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsNCksIGd1aWRlcyA9ICJjb2xsZWN0IikgJiAKICAgIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uPWMoMCwgMSkpCmZpZzRfYmJyaWdodCArICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfREVHX2hlYXRtYXAucGRmIiwgd2lkdGg9OSwgaGVpZ2h0ID0gOSkKCmBgYAoKIyMjIyBRdWljayBHTyB0ZXJtIGFuYWx5c2lzCgpgYGB7cn0KIyBpbnN0YWxsLnBhY2thZ2VzKCJlbnJpY2hSIikKbGlicmFyeShlbnJpY2hSKQoKZGJzIDwtIGxpc3RFbnJpY2hyRGJzKCkKd2Vic2l0ZUxpdmUgPC0gVFJVRQppZiAoaXMubnVsbChkYnMpKSB3ZWJzaXRlTGl2ZSA8LSBGQUxTRQppZiAod2Vic2l0ZUxpdmUpIGhlYWQoZGJzKQoKZGJzIDwtIGMoIkdPX01vbGVjdWxhcl9GdW5jdGlvbl8yMDE1IiwgIkdPX0NlbGx1bGFyX0NvbXBvbmVudF8yMDE1IiwgIkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc18yMDE1IikKZ29fbWFya2VyX2dlbmVzIDwtIGVucmljaHIobWFya2VyX2dlbmVzLCBkYnMpCmdvX2FsbF9nZW5lcyA8LSBlbnJpY2hyKGVuZG9faHZncywgZGJzKQoKcmVmX3Rlcm1zIDwtIGdvX2FsbF9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSRUZXJtW2dvX2FsbF9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSRBZGp1c3RlZC5QLnZhbHVlIDwgMC4wMV0KCmdvX3Bsb3QgPC0gZ29fbWFya2VyX2dlbmVzJEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc18yMDE1W2dvX21hcmtlcl9nZW5lcyRHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAxNSRBZGp1c3RlZC5QLnZhbHVlIDwgMC4wMSxdICU+JQogIGRwbHlyOjpmaWx0ZXIoIVRlcm0gJWluJSByZWZfdGVybXMpICU+JQogIHRvcF9uKDMwLCAtbG9nMTAoQWRqdXN0ZWQuUC52YWx1ZSkpICU+JQogIG11dGF0ZShUZXJtPWZhY3RvcihUZXJtLCBsZXZlbHM9cmV2KHVuaXF1ZShUZXJtKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKFRlcm0sIC1sb2cxMChBZGp1c3RlZC5QLnZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiR08gQmlvbG9naWNhbCBGdW5jdGlvbiIpICsgeWxhYigiLWxvZzEwKEFkai4gcC12YWx1ZSkiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KSAKCmdvX3Bsb3QgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9saXZlcl9lbmRvREVHX0dPZW5yaWNoLnBkZiIsIHdpZHRoPTksIGhlaWdodCA9IDUpCmBgYAoKQXNzZW1ibGUgZmlndXJlCmBgYHtyLCBmaWcuaGVpZ2h0PTI1LCBmaWcud2lkdGg9MTl9CmZpZzRfdG9wIC8KICAoKGZpZzRfYmxlZnQgfCAoZmlnNF9icmlnaHQxIC8gZmlnNF9iYnJpZ2h0KSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMS41KSkpICsKICBwbG90X2xheW91dCh3aWR0aHM9YygxLDEuMikpKSArCiAgcGxvdF9sYXlvdXQoaGVpZ2h0cz1jKDEsMS41KSkgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9maWc0LnBkZiIsIGhlaWdodCA9IDI2LCB3aWR0aCA9IDIyLCB1c2VEaW5nYmF0cz1GQUxTRSkKICAKYGBgCgoKCkFzc2VtYmxlIHN1cHBsZW1lbnRhcnkgZmlndXJlCgpgYGB7ciwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9N30KcDEgPC0gcGxvdF9ncmlkKHB2YWxfaGlzdCwgCiAgICAgICAgICAgICAgICB2b2xjYW5vICsgeWxhYigiLSBsb2cxMChTcGF0aWFsIEZEUikiKSwgCiAgICAgICAgICAgICAgICBmcmFjX2hpc3QsIG5yb3c9MSwKICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIikpIApjb3dwbG90OjpwbG90X2dyaWQocDEsIGdvX3Bsb3QsIHJlbF9oZWlnaHRzID0gYygxLDEuNSksIG5jb2w9MSwgbGFiZWxzID0gYygiIiwgIkQiKSkgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9saXZlcl9zdXBwbGVtZW50YXJ5LnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoPTgpCiAgCmBgYAoKPCEtLSBMZXQncyBjaGVjayB0aGUgZ2VuZXMgaWRlbnRpZmllZCBhcyBtYXJrZXJzIGZvciB0aGUgZGlzZWFzZSBzdWJ0eXBlcy4gQXJlIHRoZXkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiBEQSBuZWlnaGJvdXJob29kcz8gWWVzIHRoZXkgYXJlISAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGRpc2Vhc2VfZW5kb19tYXJrZXJzIDwtIGMoIkFDS1IxIiwgJ0NEMzQnLCJWV0ExIikgLS0+Cgo8IS0tIGRhdGEuZnJhbWUobWFya2VycyRuZWdMb2dGQ18yKSAlPiUgLS0+CjwhLS0gICBmaWx0ZXIoRkRSIDwgMC4wNSkgJT4lIC0tPgo8IS0tICAgLltkaXNlYXNlX2VuZG9fbWFya2VycyxdIC0tPgoKPCEtLSBkYXRhLmZyYW1lKG1hcmtlcnMkbmVnTG9nRkNfMSkgJT4lIC0tPgo8IS0tICAgZmlsdGVyKEZEUiA8IDAuMDUpICU+JSAtLT4KPCEtLSAgIC5bZGlzZWFzZV9lbmRvX21hcmtlcnMsXSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIFZpc3VhbGl6ZSBzb21lIG9mIHRoZSBtYXJrZXJzIHRoYXQgZGlmZmVyZW50aWF0ZSBEQSBuZWlnaGJvdXJob29kcywgYnkgcGxvdHRpbmcgdGhlIHBlcmNlbnQgb2YgY2VsbHMgZXhwcmVzc2luZyBlYWNoIGdlbmUgaW4gYSBuaG9vZC4gLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSAjIyBEZWZpbmUgcGxvdHRpbmcgZnVuY3Rpb25zIC0tPgo8IS0tIC5jYWxjdWxhdGVfbmhvb2RfcGVyY19leHByZXNzaW9uIDwtIGZ1bmN0aW9uKG1pbG8sIG5ob29kcywgZ2VuZSl7IC0tPgo8IS0tICAgZ2VuZV9jbnRzIDwtIGNvdW50cyhtaWxvKVtnZW5lLF0gLS0+CjwhLS0gICBwZXJjX2V4cHIgPC0gc2FwcGx5KG5ob29kcyhtaWxvKVtuaG9vZHNdLCBmdW5jdGlvbih4KSBzdW0oZ2VuZV9jbnRzW3hdPjApL2xlbmd0aCh4KSkgLS0+CjwhLS0gICBwZXJjX2V4cHIgPC0gc2V0TmFtZXMocGVyY19leHByLCBuaG9vZHMpIC0tPgo8IS0tICAgcmV0dXJuKHBlcmNfZXhwcikgLS0+CjwhLS0gICB9IC0tPgoKPCEtLSAucGxvdF9uaG9vZF9leHByZXNzaW9uIDwtIGZ1bmN0aW9uKG1pbG8sIG5ob29kcywgZmVhdHVyZXMpeyAtLT4KPCEtLSAgIHBlcmNfZXhwcl9tYXQgPC0gc2FwcGx5KGZlYXR1cmVzLCAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSAuY2FsY3VsYXRlX25ob29kX3BlcmNfZXhwcmVzc2lvbihtaWxvLCBuaG9vZHMsIHgpKSAtLT4KCjwhLS0gICBwbF9kZiA8LSBkYXRhLmZyYW1lKHBlcmNfZXhwcl9tYXQpICU+JSAtLT4KPCEtLSAgICAgcm93bmFtZXNfdG9fY29sdW1uKCJOaG9vZCIpICU+JSAtLT4KPCEtLSAgICAgbXV0YXRlKE5ob29kPWFzLmRvdWJsZShOaG9vZCkpICU+JSAtLT4KPCEtLSAgICAgbGVmdF9qb2luKG1pbG9fcmVzKSAlPiUgLS0+CjwhLS0gICAgIG11dGF0ZShsb2dGQ19yYW5rPXJhbmsobG9nRkMpKSAgLS0+Cgo8IS0tICAgcGxfdG9wIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgICAgICBtdXRhdGUoaXNfc2lnbmlmID0gaWZlbHNlKFNwYXRpYWxGRFIgPCAwLjEsICJTcGF0aWFsRkRSIDwgMC4xIiwgTkEpKSAlPiUgLS0+CjwhLS0gICAgICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBsb2dGQykpICsgLS0+CjwhLS0gICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9MikgKyAtLT4KPCEtLSAgICAgICBnZW9tX3BvaW50KHNpemU9MC4yKSArIC0tPgo8IS0tICAgICAgIGdlb21fcG9pbnQoZGF0YT0uJT4lIGZpbHRlcighaXMubmEoaXNfc2lnbmlmKSksIGFlcyhjb2xvcj1pc19zaWduaWYpLCBzaXplPTAuNSkgKyAtLT4KPCEtLSAgICAgICB0aGVtZV9idygpICsgLS0+CjwhLS0gICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0icmVkIiwgbmFtZT0iIikgKyAtLT4KPCEtLSAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpIC0tPgoKPCEtLSAgIHBsX2JvdHRvbSA8LSBwbF9kZiAlPiUgLS0+CjwhLS0gICAgIHBpdm90X2xvbmdlcihjb2xzPWZlYXR1cmVzLCBuYW1lc190bz0nZmVhdHVyZScsIHZhbHVlc190bz0icGVyY19leHByZXNzZWQiKSAlPiUgLS0+CjwhLS0gICAgIG11dGF0ZShmZWF0dXJlPWZhY3RvcihmZWF0dXJlLCBsZXZlbHM9ZmVhdHVyZXMpKSAlPiUgLS0+CjwhLS0gICAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgZmVhdHVyZSwgZmlsbD1wZXJjX2V4cHJlc3NlZCkpICsgIC0tPgo8IS0tICAgICBnZW9tX3RpbGUoKSArIC0tPgo8IS0tICAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249Im1hZ21hIikgKyAtLT4KPCEtLSAgICAgZ2diaW86OnRoZW1lX2NsZWFyKCkgLS0+Cgo8IS0tICAgKHBsX3RvcCAvIHBsX2JvdHRvbSkgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDIpKSAtLT4KPCEtLSB9IC0tPgo8IS0tIGBgYCAtLT4KCgo8IS0tIGBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9IC0tPgo8IS0tIGVuZG9fbmhvb2RzIDwtIGVuZG9fcmVzICU+JSAgcHVsbChOaG9vZCkgLS0+Cgo8IS0tICMjIFNlbGVjdCBnZW5lcyBhbmQgc29ydCBieSBBVUMgLS0+CjwhLS0gZmVhdHNfbmVnMiA8LSAtLT4KPCEtLSAgIGRhdGEuZnJhbWUobWFya2VycyRuZWdMb2dGQ18yKSAlPiUgIC0tPgo8IS0tICAgdG9wX24oNTAsIC0gbG9nMTAoRkRSKSkgJT4lIC0tPgo8IS0tICAgYXJyYW5nZShBVUMucG9zTG9nRkNfMSkgJT4lIC0tPgo8IS0tICAgcm93bmFtZXMoKSAtLT4KCjwhLS0gLnBsb3Rfbmhvb2RfZXhwcmVzc2lvbihsaXZlcl9taWxvLCBlbmRvX25ob29kcywgZmVhdHVyZXM9ZmVhdHMpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gQXMgZGVzY3JpYmVkIGluIHRoZSBwYXBlciwgd2UgaGF2ZSB0aGF0IGdlbmVzIGFzc29jaWF0ZWQgd2l0aCBleHRyYWNlbGx1bGFyIG1hdHJpeCBvcmdhbml6YXRpb24gKGUuZy4gVklNLCApIGFyZSBvdmVyIGV4cHJlc3NlZCAgLS0+CgoKPCEtLSBgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9IC0tPgo8IS0tICMjIFNlbGVjdCBnZW5lcyBhbmQgc29ydCBieSBBVUMgLS0+CjwhLS0gZmVhdHNfbmVnMSA8LSAtLT4KPCEtLSAgIGRhdGEuZnJhbWUobWFya2VycyRuZWdMb2dGQ18xKSAlPiUgIC0tPgo8IS0tICAgdG9wX24oNTAsIC0gbG9nMTAoRkRSKSkgJT4lIC0tPgo8IS0tICAgYXJyYW5nZShBVUMucG9zTG9nRkNfMSkgJT4lIC0tPgo8IS0tICAgcm93bmFtZXMoKSAtLT4KCjwhLS0gLnBsb3Rfbmhvb2RfZXhwcmVzc2lvbihsaXZlcl9taWxvLCBlbmRvX25ob29kcywgZmVhdHVyZXM9ZmVhdHMpIC0tPgoKPCEtLSBgYGAgLS0+Cgo8IS0tIGBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30gLS0+CjwhLS0gZmVhdHNfbmVnMXZzTmVnMiA8LSAtLT4KPCEtLSAgIGRhdGEuZnJhbWUobWFya2VycyRuZWdMb2dGQ18xKSAlPiUgIC0tPgo8IS0tICAgdG9wX24oNTAsIC0gbG9nMTAoRkRSKSkgJT4lIC0tPgo8IS0tICAgYXJyYW5nZShBVUMubmVnTG9nRkNfMikgJT4lIC0tPgo8IS0tICAgcm93bmFtZXMoKSAtLT4KCjwhLS0gLnBsb3Rfbmhvb2RfZXhwcmVzc2lvbihsaXZlcl9taWxvLCBlbmRvX25ob29kcywgZmVhdHVyZXM9ZmVhdHNfbmVnMXZzTmVnMikgLS0+CjwhLS0gYGBgIC0tPgoKCjwhLS0gTG9vayBqdXN0IGF0IEVuZG90aGVsaWEgKDUpIHdoZXJlIHlvdSBoYXZlIGJvdGggcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGZvbGQtY2hhbmdlcyAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGVuZG81X25ob29kcyA8LSBtaWxvX3JlcyAlPiUgIC0tPgo8IS0tICAgZmlsdGVyKGFubm90YXRpb25faW5kZXB0aD09IkVuZG90aGVsaWEgKDUpIiAmIGFubm90YXRpb25faW5kZXB0aF9mcmFjdGlvbiA+IDAuNykgJT4lIC0tPgo8IS0tICAgcHVsbChOaG9vZCkgLS0+Cgo8IS0tIHBlcmNfZXhwcl9tYXQgPC0gc2FwcGx5KGZlYXR1cmVzLCAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgLmNhbGN1bGF0ZV9uaG9vZF9wZXJjX2V4cHJlc3Npb24obGl2ZXJfbWlsbywgZW5kbzVfbmhvb2RzLCB4KSkgLS0+Cgo8IS0tIHBsX2RmIDwtIGRhdGEuZnJhbWUocGVyY19leHByX21hdCkgJT4lIC0tPgo8IS0tICAgcm93bmFtZXNfdG9fY29sdW1uKCJOaG9vZCIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShOaG9vZD1hcy5kb3VibGUoTmhvb2QpKSAlPiUgLS0+CjwhLS0gICBsZWZ0X2pvaW4obWlsb19yZXMpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShsb2dGQ19yYW5rPXJhbmsobG9nRkMpKSAgLS0+Cgo8IS0tIHBsX3RvcCA8LSBwbF9kZiAlPiUgLS0+CjwhLS0gICAgIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IDAuMSwgIlNwYXRpYWxGRFIgPCAwLjEiLCBOQSkpICU+JSAtLT4KPCEtLSAgICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBsb2dGQykpICsgLS0+CjwhLS0gICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPTIpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoZGF0YT0uJT4lIGZpbHRlcighaXMubmEoaXNfc2lnbmlmKSksIGFlcyhjb2xvcj1pc19zaWduaWYpLCBzaXplPTAuNSkgKyAtLT4KPCEtLSAgICAgdGhlbWVfYncoKSArIC0tPgo8IS0tICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSJyZWQiLCBuYW1lPSIiKSArIC0tPgo8IS0tICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpIC0tPgoKPCEtLSBwbF9ib3R0b20gPC0gcGxfZGYgJT4lIC0tPgo8IS0tICAgcGl2b3RfbG9uZ2VyKGNvbHM9ZmVhdHVyZXMsIG5hbWVzX3RvPSdmZWF0dXJlJywgdmFsdWVzX3RvPSJwZXJjX2V4cHJlc3NlZCIpICU+JSAtLT4KPCEtLSAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgZmVhdHVyZSwgZmlsbD1wZXJjX2V4cHJlc3NlZCkpICsgIC0tPgo8IS0tICAgZ2VvbV90aWxlKCkgKyAtLT4KPCEtLSAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ibWFnbWEiKSArIC0tPgo8IS0tICAgdGhlbWVfY2xlYXIoKSAtLT4KCjwhLS0gKHBsX3RvcCAvIHBsX2JvdHRvbSkgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDIpKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIEhvdyB0byBmaW5kIGFzc29jaWF0aW9uIGRlIG5vdm8gaW4gRW5kbyA1PyAtLT4KCjwhLS0gYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9IC0tPgo8IS0tICMjIEZpbmQgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMgaW4gdGhpcyBjbHVzdGVyIC0tPgo8IS0tIGVuZG81X21pbG8gPC0gbGl2ZXJfbWlsb1ssd2hpY2goY29sRGF0YShsaXZlcl9taWxvKVtbImFubm90YXRpb25faW5kZXB0aCJdXT09IkVuZG90aGVsaWEgKDUpIildIC0tPgo8IS0tIGRlY19lbmRvNSA8LSBtb2RlbEdlbmVWYXIoZW5kbzVfbWlsbykgLS0+CjwhLS0gZW5kbzVfaHZncyA8LSBnZXRUb3BIVkdzKGRlY19lbmRvNSwgbj0xMDAwKSAtLT4KCjwhLS0gcGVyY19leHByX21hdCA8LSBzYXBwbHkoZW5kbzVfaHZncywgZnVuY3Rpb24oeCkgLmNhbGN1bGF0ZV9uaG9vZF9wZXJjX2V4cHJlc3Npb24obGl2ZXJfbWlsbywgZW5kbzVfbmhvb2RzLCB4KSkgLS0+Cgo8IS0tIG1pbG9fcmVzX2VuZG81IDwtIG1pbG9fcmVzW3doaWNoKG1pbG9fcmVzJE5ob29kICVpbiUgZW5kbzVfbmhvb2RzKSxdIC0tPgoKPCEtLSBmY19jb3IgPC0gYXBwbHkocGVyY19leHByX21hdCwgMiwgZnVuY3Rpb24oeCkgSG1pc2M6OnJjb3JyKHgsIG1pbG9fcmVzX2VuZG81JGxvZ0ZDKSRyWzEsMl0pIC0tPgo8IS0tIGZjX2Nvcl9wdmFsIDwtIGFwcGx5KHBlcmNfZXhwcl9tYXQsIDIsIGZ1bmN0aW9uKHgpIEhtaXNjOjpyY29ycih4LCBtaWxvX3Jlc19lbmRvNSRsb2dGQykkUFsxLDJdKSAtLT4KCjwhLS0gY29yX2ZlYXRzIDwtIG5hbWVzKHdoaWNoKGFicyhmY19jb3IpID4gMC42ICYgYWJzKGZjX2Nvcl9wdmFsKSA8IDAuMDUpKSAtLT4KPCEtLSBjb3JfZmVhdHNfb3JkZXJlZCA8LSBjb3JfZmVhdHNbb3JkZXIoZmNfY29yW2Nvcl9mZWF0c10pXSAtLT4KCjwhLS0gcGxfZGYgPC0gZGF0YS5mcmFtZShwZXJjX2V4cHJfbWF0Wyxjb3JfZmVhdHNdKSAlPiUgLS0+CjwhLS0gICByb3duYW1lc190b19jb2x1bW4oIk5ob29kIikgJT4lIC0tPgo8IS0tICAgbXV0YXRlKE5ob29kPWFzLmRvdWJsZShOaG9vZCkpICU+JSAtLT4KPCEtLSAgIGxlZnRfam9pbihtaWxvX3JlcykgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGxvZ0ZDX3Jhbms9cmFuayhsb2dGQykpICAtLT4KCjwhLS0gcGxfdG9wIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgICAgbXV0YXRlKGlzX3NpZ25pZiA9IGlmZWxzZShTcGF0aWFsRkRSIDwgMC4xLCAiU3BhdGlhbEZEUiA8IDAuMSIsIE5BKSkgJT4lIC0tPgo8IS0tICAgICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGxvZ0ZDKSkgKyAtLT4KPCEtLSAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9MikgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludChzaXplPTAuMikgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludChkYXRhPS4lPiUgZmlsdGVyKCFpcy5uYShpc19zaWduaWYpKSwgYWVzKGNvbG9yPWlzX3NpZ25pZiksIHNpemU9MC41KSArIC0tPgo8IS0tICAgICB0aGVtZV9idygpICsgLS0+CjwhLS0gICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9InJlZCIsIG5hbWU9IiIpICsgLS0+CjwhLS0gICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgLS0+Cgo8IS0tIHBsX2JvdHRvbSA8LSBwbF9kZiAlPiUgLS0+CjwhLS0gICBwaXZvdF9sb25nZXIoY29scz1zdHJfcmVwbGFjZShjb3JfZmVhdHNfb3JkZXJlZCwgIi0iLCAiLiIpLCBuYW1lc190bz0nZmVhdHVyZScsIHZhbHVlc190bz0icGVyY19leHByZXNzZWQiKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoZmVhdHVyZT1mYWN0b3IoZmVhdHVyZSwgbGV2ZWxzPXN0cl9yZXBsYWNlKGNvcl9mZWF0c19vcmRlcmVkLCAiLSIsICIuIikpKSAlPiUgLS0+CjwhLS0gICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGZlYXR1cmUsIGZpbGw9cGVyY19leHByZXNzZWQpKSArICAtLT4KPCEtLSAgIGdlb21fdGlsZSgpICsgLS0+CjwhLS0gICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249Im1hZ21hIikgKyAtLT4KPCEtLSAgIHRoZW1lX2NsZWFyKCkgLS0+Cgo8IS0tIChwbF90b3AgLyBwbF9ib3R0b20pICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMSwyKSkgLS0+CjwhLS0gYGBgIC0tPgoKCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSAjIyBSdW4gY29tbW9uIFBDQSAtLT4KPCEtLSBtZXJnZWRfY250cyA8LSBjYmluZChuaG9vZEV4cHJlc3Npb24oZW5kb19taWxvKSwgbG9nY291bnRzKGVuZG9fbWlsbylbaHZncyxdKSAtLT4KPCEtLSBtZXJnZWRfY250c19zY2FsZWQgPC0gdChzY2FsZSh0KG1lcmdlZF9jbnRzKSkpIC0tPgo8IS0tIG1lcmdlZF9wY2EgPC0gQmlvY1Npbmd1bGFyOjpydW5QQ0EodChtZXJnZWRfY250c19zY2FsZWQpLCByYW5rPTMwLCBjZW50ZXI9RkFMU0UpIC0tPgo8IS0tIHBjYV9tYXQgPC0gcmJpbmQobWVyZ2VkX3BjYSR4WyhuY29sKGVuZG9fbWlsbykrMSk6KG5jb2woZW5kb19taWxvKSsobGVuZ3RoKG5ob29kcyhlbmRvX21pbG8pKSkpLF0sIG1lcmdlZF9wY2EkeFtjb2xuYW1lcyhlbmRvX21pbG8pLF0pIC0tPgo8IS0tICMjIEFkZCB0byBzbG90IG5ob29kc1JlZHVjZWREaW0gLS0+CjwhLS0gbmhvb2RSZWR1Y2VkRGltKGVuZG9fbWlsbywgIlBDQSIpIDwtIHBjYV9tYXQgLS0+Cgo8IS0tICMjIFJ1biBVTUFQIG9uIGpvaW50IFBDQSAtLT4KPCEtLSB1bWFwX291dCA8LSB1d290Ojp1bWFwKG5ob29kUmVkdWNlZERpbShlbmRvX21pbG8sICJQQ0EiKSwgbl9uZWlnaGJvcnMgPSAyMCwgbl9jb21wb25lbnRzID0gMiwgc2NhbGU9RkFMU0UpIC0tPgo8IS0tIGNvbG5hbWVzKHVtYXBfb3V0KSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikgLS0+CjwhLS0gbmhvb2RSZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKSA8LSB1bWFwX291dCAtLT4KCjwhLS0gYGBgIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gc3BsaXRfYnk9TlVMTCAtLT4KPCEtLSAjIyBKb2luIHRlc3QgcmVzdWx0cyBhbmQgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9ucyAtLT4KPCEtLSByZGltX2RmIDwtIGRhdGEuZnJhbWUobmhvb2RSZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKVssYygxLDIpXSkgLS0+CjwhLS0gY29sbmFtZXMocmRpbV9kZikgPC0gYygnWCcsJ1knKSAtLT4KCjwhLS0gbl9uaG9vZHMgPC0gbGVuZ3RoKG5ob29kcyhlbmRvX21pbG8pKSAtLT4KPCEtLSByZGltX2RmWywiTmhvb2QiXSA8LSBpZmVsc2UoMTpucm93KHJkaW1fZGYpICVpbiUgYygxOm5fbmhvb2RzKSwgYygxOm5fbmhvb2RzKSwgTkEpIC0tPgo8IS0tIHZpel9kZiAgPC0gbGVmdF9qb2luKHJkaW1fZGYsIG1pbG9fcmVzW3doaWNoKG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiKSxdLCBieT0iTmhvb2QiKSAtLT4KPCEtLSB2aXpfZGZbWyJuaEluZGV4Il1dIDwtIHVubGlzdChpZmVsc2UoIWlzLm5hKHZpel9kZiROaG9vZCksIG5ob29kSW5kZXgoZW5kb19taWxvKVt2aXpfZGYkTmhvb2RdLE5BKSkgLS0+CjwhLS0gdml6X2RmW2lzLm5hKHZpel9kZlsibmhJbmRleCJdKSwnbmhJbmRleCddIDwtIDE6bmNvbChlbmRvX21pbG8pICMgQWRkIGluZGV4IGFsc28gdG8gc2luZ2xlLWNlbGxzIC0tPgoKPCEtLSBpZiAoIWlzLm51bGwoc3BsaXRfYnkpKXsgLS0+CjwhLS0gICBzcGxpdF9kZiA8LSBkYXRhLmZyYW1lKHNwbGl0X2J5PWNvbERhdGEoZW5kb19taWxvKVssc3BsaXRfYnldKSAtLT4KPCEtLSAgIHNwbGl0X2RmWywibmhJbmRleCJdIDwtIDE6bnJvdyhzcGxpdF9kZikgLS0+CjwhLS0gICB2aXpfZGYgIDwtIGxlZnRfam9pbih2aXpfZGYsIHNwbGl0X2RmLCBieT0ibmhJbmRleCIpIC0tPgo8IS0tIH0gLS0+Cgo8IS0tIGZpbHRlcl9hbHBoYT0wLjEgLS0+CjwhLS0gIyMgRmlsdGVyIHNpZ25pZmljYW50IERBIG5ob29kcyAtLT4KPCEtLSBpZiAoIWlzLm51bGwoZmlsdGVyX2FscGhhKSkgeyAtLT4KPCEtLSAgIGlmIChmaWx0ZXJfYWxwaGEgPiAwKSB7IC0tPgo8IS0tICAgICB2aXpfZGYgPC0gbXV0YXRlKHZpel9kZiwgbG9nRkMgPSBpZmVsc2UoU3BhdGlhbEZEUiA+IGZpbHRlcl9hbHBoYSwgTkEsIGxvZ0ZDKSkgLS0+CjwhLS0gICB9IC0tPgo8IS0tIH0gLS0+Cgo8IS0tICMjIFBsb3QgLS0+CjwhLS0gcHRfc2l6ZT0xIC0tPgo8IS0tIG5ob29kX3JlZHVjZWRfZGltcz0iVU1BUCIgLS0+CjwhLS0gY29tcG9uZW50cz1jKDEsMikgLS0+CjwhLS0gICBwbCA8LSAtLT4KPCEtLSAgICAgZ2dwbG90KGRhdGEgPSBhcnJhbmdlKHZpel9kZiwgYWJzKGxvZ0ZDKSksIC0tPgo8IS0tICAgICAgICAgICAgYWVzKFgsIFkpKSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9ICcnKSwgc2l6ZSA9IHB0X3NpemUgLyAzLCBhbHBoYSA9IDAuNSkgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludCggLS0+CjwhLS0gICAgICAgZGF0YSA9IC4gJT4lIGZpbHRlcighaXMubmEoU3BhdGlhbEZEUikpLCAtLT4KPCEtLSAgICAgICBhZXMoZmlsbCA9IGxvZ0ZDKSwgLS0+CjwhLS0gICAgICAgc2l6ZSA9IHB0X3NpemUsIC0tPgo8IS0tICAgICAgIHN0cm9rZSA9IDAuMSwgLS0+CjwhLS0gICAgICAgIyBjb2xvdXI9ImJsYWNrIiwgLS0+CjwhLS0gICAgICAgc2hhcGUgPSAyMSAtLT4KPCEtLSAgICAgKSArIC0tPgo8IS0tICAgICBzY2FsZV9maWxsX2dyYWRpZW50MiggLS0+CjwhLS0gICAgICAgbWlkcG9pbnQgPSAwLCAtLT4KPCEtLSAgICAgICBoaWdoID0gInJlZCIsIC0tPgo8IS0tICAgICAgIGxvdyA9ICJibHVlIiwgLS0+CjwhLS0gICAgICAgbmFtZSA9ICJsb2ctRkMiIC0tPgo8IS0tICAgICApICsgLS0+CjwhLS0gICAgIHhsYWIocGFzdGUobmhvb2RfcmVkdWNlZF9kaW1zLCBjb21wb25lbnRzWzFdLCBzZXA9Il8iKSkgKyAtLT4KPCEtLSAgICAgeWxhYihwYXN0ZShuaG9vZF9yZWR1Y2VkX2RpbXMsIGNvbXBvbmVudHNbMl0sIHNlcD0iXyIpKSAtLT4KCjwhLS0gICBpZiAoIWlzLm51bGwoc3BsaXRfYnkpKSB7IC0tPgo8IS0tICAgICBwbCA8LSBwbCArIGZhY2V0X3dyYXAoc3BsaXRfYnl+LikgLS0+CjwhLS0gICB9IC0tPgo8IS0tICAgaWYgKCFpcy5udWxsKGZpbHRlcl9hbHBoYSkpIHsgLS0+CjwhLS0gICAgIHBsIDwtIHBsICsgLS0+CjwhLS0gICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9ICdncmV5JywgbGFiZWwgPSBwYXN0ZSgiU3BhdGlhbEZEUiA+Iiwgcm91bmQoZmlsdGVyX2FscGhhLCAyKSkpICsgLS0+CjwhLS0gICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCggLS0+CjwhLS0gICAgICAgICAnJywgLS0+CjwhLS0gICAgICAgICBvdmVycmlkZS5hZXMgPSBsaXN0KCAtLT4KPCEtLSAgICAgICAgICAgc2hhcGUgPSAyMSwgLS0+CjwhLS0gICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIC0tPgo8IS0tICAgICAgICAgICBmaWxsID0gImdyZXk1MCIsIC0tPgo8IS0tICAgICAgICAgICBzaXplID0gcHRfc2l6ZSwgLS0+CjwhLS0gICAgICAgICAgIGFscGhhID0gMSwgLS0+CjwhLS0gICAgICAgICAgIHN0cm9rZSA9IDAuMSAtLT4KPCEtLSAgICAgICAgICkgLS0+CjwhLS0gICAgICAgKSkgLS0+CjwhLS0gICB9IGVsc2UgeyAtLT4KPCEtLSAgICAgcGwgPC0gcGwgKyAtLT4KPCEtLSAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gJ2dyZXknKSArIC0tPgo8IS0tICAgICAgIGd1aWRlcyhjb2xvcj0ibm9uZSIpIC0tPgo8IS0tICAgfSAtLT4KCjwhLS0gICBwbCA8LSBwbCArIC0tPgo8IS0tICAgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE2KSArIC0tPgo8IS0tICAgICB0aGVtZSggLS0+CjwhLS0gICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgLS0+CjwhLS0gICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCAtLT4KPCEtLSAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAtLT4KPCEtLSAgICAgKSAtLT4KPCEtLSBwbCAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBlbmRvX21pbG8gPC0gc2NhdGVyOjpydW5QQ0EoZW5kb19taWxvLCBzdWJzZXRfcm93PWh2Z3MpIC0tPgo8IS0tIGBgYCAtLT4KCgoKPCEtLSAtLS0gLS0+CjwhLS0gIyMgT2xkIChiZWZvcmUgSSBnb3QgZGF0YXNldCBmcm9tIGF1dGhvcnMpIC0tPgoKPCEtLSBVc2luZyBkYXRhIGZyb20gW1JhbWFjaGFuZHJhbiBldCBhbC4gMjAxOV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDE5LTE2MzEtMyNTZWMxKSAoR0VPIGFjY2Vzc2lpb246IEdTRTEzNjEwMykuICAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGh1bWFuX2ZpbGVzIDwtIGxpc3QuZmlsZXMoIn4vRG93bmxvYWRzL0dTRTEzNjEwM19SQVciLCBwYXR0ZXJuPSJHU000MDQxMS4uX2hlYWx0aHl8Y2lycmhvdGljIiwgZnVsbC5uYW1lcyA9IFRSVUUpICAtLT4KCjwhLS0gcHJlZml4ZXMgPC0gc3RyX3JlbW92ZShodW1hbl9maWxlcywgImJhcmNvZGVzLnRzdi5nenxnZW5lcy50c3YuZ3p8bWF0cml4Lm10eC5neiIpICU+JSAtLT4KPCEtLSAgICMgc3RyX3JlbW92ZSgiLisvIikgJT4lIC0tPgo8IS0tICAgdW5pcXVlKCkgIC0tPgoKPCEtLSBzY2VfbHMgPC0gbGFwcGx5KHByZWZpeGVzLCBmdW5jdGlvbih4KSByZWFkMTB4Q291bnRzKHgsIHR5cGU9InByZWZpeCIpKSAtLT4KPCEtLSBsaXZlcl9zY2UgPC0gcHVycnI6OnJlZHVjZShzY2VfbHMsIGNiaW5kKSAtLT4KCjwhLS0gIyMgTWFrZSBjb2xEYXRhIGluZm8gLS0+CjwhLS0gbmV3X2NvbGRhdGEgPC0gY29sRGF0YShsaXZlcl9zY2UpICU+JSAtLT4KPCEtLSAgIGRhdGEuZnJhbWUoKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoU2FtcGxlPXN0cl9yZW1vdmUoU2FtcGxlLCAiLisvIikgJT4lIHN0cl9yZW1vdmUoIl8kIikpICU+JSAtLT4KPCEtLSAgIHNlcGFyYXRlKFNhbXBsZSwgaW50bz1jKCJjb2wxIiwgIlBhdGllbnQiLCAiU29ydCIpLCBzZXAgPSAiXyIsIHJlbW92ZT1GQUxTRSkgJT4lICAtLT4KPCEtLSAgIG11dGF0ZShDb25kaXRpb249c3RyX3JlbW92ZShQYXRpZW50LCAiLiQiKSkgJT4lIC0tPgo8IS0tICAgc2VsZWN0KC1jb2wxKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoQ2VsbF9pZCA9IHN0cl9jKFNhbXBsZSwgIl8iLEJhcmNvZGUpKSAlPiUgLS0+CjwhLS0gICBjb2x1bW5fdG9fcm93bmFtZXMoIkNlbGxfaWQiKSAtLT4KCjwhLS0gY29sbmFtZXMobGl2ZXJfc2NlKSA8LSByb3duYW1lcyhuZXdfY29sZGF0YSkgLS0+CjwhLS0gY29sRGF0YShsaXZlcl9zY2UpIDwtIERhdGFGcmFtZShuZXdfY29sZGF0YSkgLS0+Cgo8IS0tICMgc2F2ZVJEUyhsaXZlcl9zY2UsICJ+L0dTRTEzNjEwM19TaW5nbGVDZWxsRXhwZXJpbWVudC5SRFMiKSAtLT4KPCEtLSBgYGAgLS0+CjwhLS0gYGBge3J9IC0tPgo8IS0tIGxpdmVyX3NjZSA8LSByZWFkUkRTKCJ+L0dTRTEzNjEwM19TaW5nbGVDZWxsRXhwZXJpbWVudC5SRFMiKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIFFDIG1ldHJpY3Mgc2hvdyB0aGF0IHRoZSBvdXRsaWVyIGNlbGxzIGFyZSBhbHJlYWR5IGZpbHRlcmVkIChmb2xsb3dpbmcgW3RoaXNdKGh0dHBzOi8vb3NjYS5iaW9jb25kdWN0b3Iub3JnL292ZXJ2aWV3Lmh0bWwjZGF0YS1wcm9jZXNzaW5nLWFuZC1kb3duc3RyZWFtLWFuYWx5c2lzKSkgLS0+Cgo8IS0tIGBgYHtyLCBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD04fSAtLT4KPCEtLSAjIGlzLm1pdG8gPC0gZ3JlcGwoIl5NVC0iLCByb3duYW1lcyhsaXZlcl9zY2UpKSAtLT4KPCEtLSBxY3N0YXRzIDwtIHBlckNlbGxRQ01ldHJpY3MobGl2ZXJfc2NlKSAtLT4KCjwhLS0gY29sRGF0YShsaXZlcl9zY2UpIDwtIGNiaW5kKGNvbERhdGEobGl2ZXJfc2NlKSwgcWNzdGF0cykgLS0+Cgo8IS0tIHBsb3RDb2xEYXRhKGxpdmVyX3NjZSwgeD0iU2FtcGxlIiwgeSA9ICJ0b3RhbCIsIG90aGVyX2ZpZWxkcyA9ICJDb25kaXRpb24iKSArIC0tPgo8IS0tICAgc2NhbGVfeV9sb2cxMCgpICsgLS0+CjwhLS0gICBmYWNldF93cmFwKH5Db25kaXRpb24sIHNjYWxlcyA9ICJmcmVlIikgKyAtLT4KPCEtLSAgIGdndGl0bGUoInRvdGFsIGNvdW50cyIpICAtLT4KCjwhLS0gcGxvdENvbERhdGEobGl2ZXJfc2NlLCB4PSJTYW1wbGUiLCB5ID0gImRldGVjdGVkIiwgb3RoZXJfZmllbGRzID0gIkNvbmRpdGlvbiIpICsgLS0+CjwhLS0gICBmYWNldF93cmFwKH5Db25kaXRpb24sIHNjYWxlcyA9ICJmcmVlIikgKyAtLT4KPCEtLSAgIGdndGl0bGUoIkRldGVjdGVkIGdlbmVzIikgIC0tPgoKPCEtLSBgYGAgLS0+Cgo8IS0tICMjIyBOb3JtYWxpemF0aW9uIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gbGliX3NmIDwtIGxpYnJhcnlTaXplRmFjdG9ycyhsaXZlcl9zY2UpIC0tPgo8IS0tIGhpc3QobG9nMTAobGliX3NmKSwgeGxhYj0iTG9nMTBbU2l6ZSBmYWN0b3JdIiwgY29sPSdncmV5ODAnKSAtLT4KPCEtLSBgYGAgLS0+CjwhLS0gYGBge3J9IC0tPgo8IS0tIHNldC5zZWVkKDEwMCkgLS0+CjwhLS0gbGl2ZXJfc2NlIDwtIGxvZ05vcm1Db3VudHMobGl2ZXJfc2NlKSAtLT4KPCEtLSBhc3NheU5hbWVzKGxpdmVyX3NjZSkgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSAjIyMgRmVhdHVyZSBzZWxlY3Rpb24gLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBsaWJyYXJ5KHNjcmFuKSAtLT4KPCEtLSBkZWNfbGl2ZXIgPC0gbW9kZWxHZW5lVmFyKGxpdmVyX3NjZSkgLS0+Cgo8IS0tICMgVmlzdWFsaXppbmcgdGhlIGZpdDogLS0+CjwhLS0gZml0X2xpdmVyIDwtIG1ldGFkYXRhKGRlY19saXZlcikgLS0+CjwhLS0gcGxvdChmaXRfbGl2ZXIkbWVhbiwgZml0X2xpdmVyJHZhciwgeGxhYj0iTWVhbiBvZiBsb2ctZXhwcmVzc2lvbiIsIC0tPgo8IS0tICAgICB5bGFiPSJWYXJpYW5jZSBvZiBsb2ctZXhwcmVzc2lvbiIpIC0tPgoKPCEtLSBodmdzIDwtIGdldFRvcEhWR3MoZGVjX2xpdmVyLCBuPTMwMDApIC0tPgo8IS0tIGBgYCAtLT4KCgoKPCEtLSAjIyMgRGltIHJlZHVjdGlvbiAtLT4KCjwhLS0gYGBge3IsIGZpZy5oZWlnaHQ9MTQsIGZpZy53aWR0aD0xNH0gLS0+CjwhLS0gbGl2ZXJfc2NlIDwtIHNjYXRlcjo6cnVuUENBKGxpdmVyX3NjZSwgc3Vic2V0X3Jvdz1odmdzLCBuY29tcG9uZW50cz0zMCkgLS0+CjwhLS0gcmVkdWNlZERpbShsaXZlcl9zY2UsICJQQ0EiKSA8LSByZWR1Y2VkRGltKGxpdmVyX3NjZSwgIlBDQSIpWywxOjExXSAtLT4KPCEtLSBwbG90UENBKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJDb25kaXRpb24iLCBuY29tcG9uZW50cz0zKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tIGBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fSAtLT4KPCEtLSBsaXZlcl9zY2UgPC0gcnVuVU1BUChsaXZlcl9zY2UsIGRpbXJlZD0iUENBIiwgbmNvbXBvbmVudHM9MikgLS0+Cgo8IS0tIHNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9IkNvbmRpdGlvbiIsIHBvaW50X2FscGhhPTEsICBwb2ludF9zaXplPTAuOCkgIC0tPgo8IS0tIHNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9IlNvcnQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkgLS0+CjwhLS0gc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iUGF0aWVudCIsIHBvaW50X2FscGhhPTAuMywgIHBvaW50X3NpemU9MC41KSAtLT4KPCEtLSBgYGAgLS0+CjwhLS0gYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0gLS0+CjwhLS0gcm93bmFtZXMobGl2ZXJfc2NlKSA8LSByb3dEYXRhKGxpdmVyX3NjZSkkU3ltYm9sIC0tPgo8IS0tIHNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9IkNEM0QiLCBwb2ludF9hbHBoYT0wLjMsIHBvaW50X3NpemU9MC41KSAtLT4KPCEtLSBgYGAgLS0+CgoKCg==